home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / viewers / streader.lzh / STREADER.LST < prev    next >
File List  |  1990-05-11  |  80KB  |  2,455 lines

  1. ' ****************************************************************************
  2. ' *                                                                          *
  3. ' *                             S T  R E A D E R                             *
  4. ' *                               Version 3.10                               *
  5. ' *                                                                          *
  6. ' *                               Program Code                               *
  7. ' *               © 1990 By Sterling K. Webb, SKWare One, Inc.               *
  8. ' *                   P. O. Box 277, Bunker Hill, IL 62014                   *
  9. ' *                                                                          *
  10. ' *                       GFA BASIC © GFA SYSTEMTECHNIK                      *
  11. ' *                                                                          *
  12. ' *                                                                          *
  13. ' ****************************************************************************
  14. '
  15. '
  16. ' ****************************************************************************
  17. ' *                        ST READER PROGRAM FUNCTIONS                       *
  18. ' ****************************************************************************
  19. '
  20. '   * 80-column display in all three ST resolutions (yes, even in low!)
  21. '
  22. '   * text display in either system font on either monitor.
  23. '     (25 or 50 lines in mono; 25 or 12 lines in color)
  24. '
  25. '   * text display in DEGAS-format fonts (like TEMPUS), but
  26. '     with up to ten loaded fonts on-line at one time.
  27. '
  28. '   * converts 1stWord files to Ascii text and Ascii to 1stWord.
  29. '
  30. '   * fast forward and reverse search with querry.
  31. '
  32. '   * print or save a file or any portion of a file.
  33. '
  34. '   * screen text windows (looks a lot like EMACS): open two windows
  35. '     on a single document with independent scrolling, search, etc.
  36. '
  37. '   * can be installed with text filetypes as applications (runs
  38. '     automatically when an installed filetype is double-clicked).
  39. '
  40. '   * fast, flickerless screen updating.
  41. '
  42. '   * extensively annotated program text, contains modifiable routines
  43. '     that can be used to install custom fonts in your own programs,
  44. '     allow you to implement text windows, play with the Line A Tables
  45. '     (bombs away!), talk to your shifter chip, find the Line A address
  46. '     (even in GFA Basic 2)!
  47. '
  48. '   * runs under GFA Basic version 2.0, 3.0, 3.07 with GFA3 compiled
  49. '     version provided.
  50. '
  51. '   * tested on 1040ST, Mega4, with old ROM's, with intermediate ROM's, and
  52. '     with Rainbow TOS version 1.4 (PS: it works on all of them!)
  53. '
  54. '   * placed in Public Domain June 1, 1990, with the customary dis-
  55. '     claimers about its use, suitability, applicability, worthiness,
  56. '     and ancestry, without any warranty express or implied... and so
  57. '     forth.
  58. '
  59. ' ****************************************************************************
  60. ' *                    SECTION 0: PROGRAM INITIALIZATION                     *
  61. ' ****************************************************************************
  62. '
  63. ' first off, gather the user resolution
  64. Rez%=Xbios(4)
  65. ' save it under another name, so we can restore it
  66. ' if we change resolutions, which we just might do
  67. Original_rez%=Rez%
  68. ' save the user's palette
  69. @Palette_saver
  70. ' save the user's drive selection
  71. Use_drive%=Gemdos(25)+1
  72. ' if user in low rez, switch him to medium
  73. If Rez%=0
  74.   Void Xbios(5,L:-1,L:-1,1)
  75. Endif
  76. ' gather the current operating resolution
  77. Rez%=Xbios(4)
  78. ' calculate the y-coordinate of the bottom_line
  79. Bline%=199+((Rez%-1)*200)
  80. ' calculate the desktop fill appropriate to the resolution
  81. Let Fill%=8\Rez%
  82. ' define the program palette
  83. C0%=&H777
  84. C3%=&H0
  85. C1%=&H770
  86. C2%=&H70
  87. ' set the program palette
  88. Setcolor 0,C0%
  89. Setcolor 1,C1%
  90. Setcolor 2,C2%
  91. Setcolor 3,C3%
  92. ' define those neat little arrows as charatcers because...
  93. ' GFA 3.07 WILL NOT LOAD a .LST file containing a printed Chr$(3)!
  94. C1$=Chr$(1)
  95. C2$=Chr$(2)
  96. C3$=Chr$(3)
  97. C4$=Chr$(4)
  98. ' this SBR works in GFA Version 2 and could be adapted to any language
  99. @Find_linea_address
  100. ' name these address locations in the Line A Variable Tables:
  101. ' these are the addresses used by the GFA PRINT command, not by
  102. ' the TEXT command or by GEM itself.
  103. '
  104. ' pointer to the location of the font data (character set)
  105. Font_data_adr%=Line_a_adr%-22
  106. ' this one is really neat:
  107. ' the address of an offset read by the shifter chip itself
  108. ' it works like this: if you stuck 16000 in this address,
  109. ' the shifter chip would leave the first 16000 bytes of
  110. ' screen memory alone and start screen operations halfway
  111. ' down the physical monitor screen. Hmmm... that's clipping!
  112. Shifter_adr%=Line_a_adr%-30
  113. ' stores the number of bytes in a single print line, i.e.,
  114. ' how far through the screen memory the console driver advances
  115. ' for the next print line when a linefeed is received or forced
  116. Ram_line_adr%=Line_a_adr%-40
  117. ' the maximum number of print lines on a screen minus one
  118. ' (lines are numbered from zero)
  119. Max_line_adr%=Line_a_adr%-42
  120. ' where the console driver reads height of the character cell in scan lines
  121. Cell_height_adr%=Line_a_adr%-46
  122. ' set up tables to hold these values for each of a total of twelve fonts
  123. Dim Font_data_address%(12)
  124. Dim Cell_height%(12)
  125. Dim Max_line%(12)
  126. Dim Ram_line%(12)
  127. Dim Font_size%(12)
  128. ' this SBR creates the above Table Values for the two System Fonts
  129. @Font_fitter
  130. ' checks for size of effective screen in bytes
  131. @Check_screen(Font%)
  132. ' we'll begin in the usual native-to-the-resolution system font
  133. Nonsystem_text_flag!=False
  134. ' the ten fonts refer to loadable Degas-format fonts
  135. ' the "+2" you see in the indices is because loaded fonts
  136. ' are in addition to the two system fonts already available
  137. Dim Font$(10)
  138. ' initially, we'll fill all the fonts with copies of the
  139. ' current system font, so that after we load in the 128
  140. ' characters of a Degas font, we'll still have the upper
  141. ' half of the ST's 256 characters... We'll have to do this
  142. ' again later, so we'll have both 8-high and 16-high fonts
  143. ' with the right back end characters... Somehow I feel safer with'em full
  144. For I%=0 To 9
  145.   Font$(I%)=String$(4096,0)
  146.   Bmove Font_data_address%(1),Varptr(Font$(I%)),4096
  147.   ' initialize these values for the system fonts:
  148.   ' cell_height = the height of the character cell in scan lines
  149.   If Rez%=2
  150.     Cell_height%(I%+2)=16
  151.   Else
  152.     Cell_height%(I%+2)=8
  153.   Endif
  154.   ' max_line = the highest numbered print line possible on a screen
  155.   ' (lines are numbered from 0)
  156.   Max_line%(I%+2)=24
  157.   ' ram_line = the size in bytes of one print line in screen memory
  158.   Ram_line%(I%+2)=1280
  159.   ' a marker for native=0 or non-native=1 fonts (relative to rez)
  160.   Font_size%(I%+2)=0
  161. Next I%
  162. ' it's IMPORTANT to exit through the close_out routine,
  163. ' so as to reset resolution, fonts, shifter chip, if required.
  164. On error gosub End
  165. ' table for window parameters:
  166. ' the starting point of the window on the screen...
  167. Dim Windtop%(2)
  168. ' ...and the height of the window in print lines
  169. Dim Windhi%(2)
  170. ' initial window set up
  171. @Set_windows
  172. ' we also need a pointer to where we are in the document for each window
  173. Dim Windex%(2)
  174. ' ...and the flag set to show we do not have multiple windows at startup
  175. Windows!=False
  176. ' an empty string used to wipe a windowed area clean
  177. Let Eraser$=String$(32000,0)
  178. ' we also need an off-screen printing area allocated in memory
  179. Offscreen$=String$(32255,0)
  180. ' this is the number of menu lines for the bottom of the screen ledger_line
  181. M_num%=12
  182. ' here they are...
  183. Dim T$(M_num%)
  184. T$(0)=" ST READER by SKWare One © 1990 by S. K. Webb     <Esc> <Tab> shifts Menu Line. "
  185. T$(1)=" Page:"+C2$+"  Page:"+C1$+"  Line Up:"+C4$+"  Line Down:"+C3$+" Start:<Home> End:CTRL+<Home> Quit:<Undo>"
  186. T$(2)=" ½Page:CNTL+"+C4$+"  ½Page:CNTL+"+C3$+"  Numbers 1 to 9:Repeat Last Screen Command n Times  "
  187. T$(3)=" Convert "+C3$+" Ascii:<Help>   "+C3$+" 1stWord:CNTL+<Help>  Save:CNTL+<S>   Print:CNTL+<P> "
  188. T$(4)=" Mark Up:CNTL+<U>  Mark Down:CNTL+<D>  Block Start:CNTL+<A>  Block End:CNTL+<Z> "
  189. T$(5)=" Reset Drive:CNTL+<R>    Clean Up Screen Display:CNTL+<C>   Strip Tabs:CNTL+<T> "
  190. T$(6)=" Toggle Screen Black/White:CNTL+<B>     Toggle Text Size [SYSTEM FONT]:CNTL+<X> "
  191. T$(7)=" Toggle to AltFont:CNTL+<F>  Load New Font:CNTL+<N>  Exchange AltFonts:FuncKeys "
  192. T$(8)=" Search with Querry:CNTL+<Q>    Reverse Search:ALT+<Q>   Show Position:CNTL+<=> "
  193. T$(9)=" Increase Margin:CNTL+<M>   Decrease Margin:ALT+<M>  Toggle View Style:CNTL+<V> "
  194. T$(10)=" Open/Toggle Window:CNTL+<W> Shrink Window:<-> Grow Window:<+> Unwindow:ALT+<W> "
  195. T$(11)="    Special Thanks to Eastside Atari Users' Group; Alton, IL and Metro East     "
  196. ' console code for inverse print
  197. Inv$=Chr$(27)+"p"
  198. ' console code for normal print
  199. Norm$=Chr$(27)+"q"
  200. ' console code for automatic character wrap
  201. Over_flow$=Chr$(27)+"v"
  202. ' console code for no automatic character wrap
  203. No_flow$=Chr$(27)+"w"
  204. ' turn off the automatic character wrap
  205. Print No_flow$;
  206. ' a string of spaces to hold the command tail out of the basepage
  207. Tail_length%=Peek(Basepage+128)
  208. If Tail_length%>0
  209.   Command_line$=String$(Tail_length%,32)
  210.   ' fill the empty string to see if a document filetype has been clicked on
  211.   Bmove Basepage+129,Varptr(Command_line$),Tail_length%
  212. Else
  213.   Command_line$=""
  214.   Trick!=True
  215.   @Drive
  216.   @Tidy
  217. Endif
  218. Trick!=False
  219. ' Gee, why does all this remind me of CP/M and the CCP?
  220. '
  221. ' ****************************************************************************
  222. ' *                             SECTION 1: MAIN                              *
  223. ' ****************************************************************************
  224. '
  225. ' label for a constructed loop
  226. Luper:
  227. ' set tab at zero
  228. Clr Tb%
  229. Tabs!=False
  230. ' if not called by an installed application (document filetype),
  231. ' have the user select his own file to read
  232. If Len(Command_line$)<2 Or Kexit%>0
  233.   Fileselect Path$,"",File$
  234.   If Len(File$)=0
  235.     If Kexit%>0
  236.       @Alert(2,"  |Do You Wish to Exit|      to GEM?   |  ",2," No | Yes ",Dummie%)
  237.       If Dummie%=1
  238.         Clr Kexit%
  239.         Clr C%
  240.         Clr Cc%
  241.         Goto Lupey
  242.       Else
  243.         @End
  244.       Endif
  245.     Else
  246.       @End
  247.     Endif
  248.   Endif
  249.   Command_line$=""
  250.   Erase Type$()
  251.   Index%=1
  252. Else
  253.   File$=Command_line$
  254. Endif
  255. ' clear the KEY EXIT flag
  256. Clr Kexit%
  257. ' wait for the clicks to die down...
  258. Repeat
  259. Until Mousek=0
  260. ' strip the leading root symbol "\" for printing
  261. If Asc(File$)=92
  262.   P_file$=Right$(File$,Len(File$)-1)
  263. Else
  264.   P_file$=File$
  265. Endif
  266. ' dump the rodent
  267. Hidem
  268. ' divide the free memory into two equal halves
  269. Fr%=Fre(0)-10000
  270. S%=Fr%\2
  271. ' calculate maximum number of full ascii strings it can hold
  272. Ts%=(S%\82)+1
  273. Ar$=Str$(S%)
  274. ' set up dimensioned strings to hold the lines of the text file
  275. Dim Type$(Ts%)
  276. ' define a carriage return
  277. Cr$=Chr$(13)+Chr$(10)
  278. ' pad the type strings
  279. F$=String$(82,32)
  280. For I%=1 To Ts%-1
  281.   Type$(I%)=F$
  282. Next I%
  283. ' open the file and measure its length
  284. Open "I",#1,File$
  285. Ex%=Lof(#1)
  286. ' suck in a test string to guage what kind of file it is
  287. If Ex%>255
  288.   Test$=Input$(255,#1)
  289. Else
  290.   Test$=Input$(Ex%,#1)
  291. Endif
  292. Close #1
  293. ' look for a carriage return in the test string
  294. X0%=Instr(Test$,Cr$)
  295. Test$=""
  296. ' some kinds of files we can't or don't want to load
  297. If Ex%>S%
  298.   @Too_long_abort
  299. Endif
  300. If X0%=0
  301.   @Non_text_abort
  302. Endif
  303. If X0%>242
  304.   @Long_line_abort
  305. Endif
  306. If Kexit%>0
  307.   Goto File_check
  308. Endif
  309. ' establish a dummie array to serve as a reserved memory buffer
  310. Dim T%((Ex%\4)+1)
  311. ' set up a loading screen display that looks sort of like a desktop
  312. @Tidy                     ! this is just our old friend CLearScreen
  313. If (Rez%=2 And Font_size%(Font%)=1) Or (Rez%=1 And Font_size%(Font%)=0)
  314.   Bound%=17
  315. Else
  316.   Bound%=32
  317. Endif
  318. ' remove the line boundary from filled figures
  319. ' (identical to GFA3's BOUNDARY 0 command)
  320. Dpoke Contrl,104
  321. Dpoke Contrl+6,1
  322. Dpoke Intin,0
  323. Vdisys
  324. ' clear the top of the display screen
  325. Deffill 0,2,8
  326. Pbox 0,Bound%,639,Bline%
  327. ' fake a desktop-look
  328. Deffill 3,2,Fill%
  329. Pbox 0,Bound%,639,Bline%
  330. ' if we were originally in low rez, the pbox will
  331. ' only cover half the screen, so we copy it to the right side...
  332. If Original_rez%=0
  333.   Get 1,Bound%,319,Bline%,Desk$
  334.   Vsync
  335.   Put 320,Bound%,Desk$
  336.   Desk$=""
  337. Endif
  338. ' switch to system font
  339. @Font_check_in
  340. ' print the header
  341. Print Inv$;
  342. Print At(1,1);"                 ST READER by S. K. Webb and SKWare One  © 1990                        ";
  343. Print Norm$;
  344. Print At(1,2);
  345. @Clear
  346. Print " LOADING   ";P_file$;"   Length of File: ";Str$(Ex%);" Bytes";
  347. ' load the file
  348. Bload File$,Varptr(T%(0))
  349. Print At(1,2);
  350. @Clear
  351. ' if compiled in GFA2:
  352. ' Print " ";P_file$;" LOADed. FORMAT requires ";Left$(Str$(Ex%/7565),6);" seconds for ";Str$(Ex%);" bytes.";
  353. ' if compiled in GFA3:
  354. Print " ";P_file$;" LOADed. FORMAT requires ";Left$(Str$(Ex%/24992),6);" seconds for ";Str$(Ex%);" bytes.";
  355. ' compiled in GFA2, it formats 7565 characters per second
  356. ' for maximum speed in GFA3 compilation, replace PEEK() with BYTE{}
  357. ' (it's faster in GFA3, formatting at 24992 characters per second!)
  358. ' or you could replace the whole thing with GFA3's RECALL command
  359. ' (however, RECALL strips the carriage returns from strings, and it
  360. ' makes no provision for dealing with long lines... That's up to you.)
  361. '
  362. ' here's the actual formatting routine:
  363. '
  364. N%=1       ! the index of the type string
  365. I%=0       ! pointer to our position in the filedata
  366. Li%=I%     ! pointer to the pointer position after the last completed line
  367. Repeat
  368.   Repeat
  369.     ' seek through the data for a linefeed. (If the text does not use
  370.     ' the chr$(13)+chr$(10) combination, this may have to be modified...)
  371.     A%=Peek(Varptr(T%(0))+I%)
  372.     Inc I%
  373.   Until A%=10 Or I%=Ex%
  374.   ' if the line is less than 80 characters plus carriage return/linefeed
  375.   ' move it to the type string indexed by N%
  376.   If I%-Li%=<82
  377.     Bmove Varptr(T%(0))+Li%,Varptr(Type$(N%)),I%-Li%
  378.   Else
  379.     ' if the lines are longer, we break them up...
  380.     While I%-Li%>82
  381.       Bmove Varptr(T%(0))+Li%,Varptr(Type$(N%)),80
  382.       Type$(N%)=Left$(Type$(N%),80)+Cr$
  383.       Li%=Li%+80
  384.       Inc N%
  385.     Wend
  386.     Bmove Varptr(T%(0))+Li%,Varptr(Type$(N%)),I%-Li%
  387.   Endif
  388.   ' truncate the type string if needed
  389.   Type$(N%)=Left$(Type$(N%),I%-Li%)
  390.   ' update the back pointer
  391.   Li%=I%
  392.   ' update the type string index
  393.   Inc N%
  394. Until I%=Ex% Or N%=Ts%-1
  395. ' the "top" is the number_of_type$
  396. Top%=N%
  397. ' get rid the fake desktop display
  398. @Tidy
  399. ' dump the loading array and empty the unused type strings
  400. Erase T%()
  401. For I%=Top%+1 To Ts%-1
  402.   Type$(I%)=""
  403. Next I%
  404. ' we start with the first line of the file
  405. Index%=1
  406. ' a positive heading means to display the file from first to last
  407. ' a negative heading means to display the file from last to first
  408. Heading%=1
  409. ' prints the menu line
  410. @Ledger_line
  411. Lupey:
  412. ' prints the screen
  413. @Screen_print
  414. ' look for user input
  415. @Key
  416. ' this is the bottom of the constructed loop
  417. File_check:
  418. @Alert(2,"  |Do You Wish to Read|   Another File?|  ",1," No | Yes ",Dummie%)
  419. ' we can go around again...
  420. If Dummie%=2
  421.   Goto Luper
  422. Endif
  423. If Dummie%=1
  424.   @Alert(2,"  |Do You Wish to Exit|      to GEM?   |  ",2," No | Yes ",Dummie%)
  425.   If Dummie%=1
  426.     Clr Kexit%
  427.     Clr C%
  428.     Clr Cc%
  429.     Goto Lupey
  430.   Else
  431.     @End
  432.   Endif
  433. Endif
  434. ' ...or we can quit (we never get here, but I have a neatness compulsion)
  435. @End
  436. '
  437. ' ****************************************************************************
  438. ' *                          SECTION 2: KEY READERS                           *
  439. ' ****************************************************************************
  440. '
  441. Procedure Key
  442.   Repeat
  443.     C$=Inkey$
  444.     ' code one-byte keys as C%, two-byte keys as Cc%
  445.     ' CNTL+Key returns one-byte codes: CNTL+A=1, CNTL+B=2, CNTL+C=3, etc.
  446.     ' ALT+Key returns two-byte codes based on key-position on the keyboard
  447.     If Len(C$)=2
  448.       Cc%=Asc(Right$(C$))
  449.       If Cc%=98
  450.         ' check for CNTL+<Help> key combination
  451.         Dpoke Contrl,128
  452.         Vdisys
  453.         Flag%=Dpeek(Intout)
  454.       Endif
  455.     Endif
  456.     If Len(C$)=1
  457.       C%=Asc(C$)
  458.     Endif
  459.     ' CNTL+B = toggle background color
  460.     If C%=2
  461.       If Black_flag%=0
  462.         Setcolor 0,C3%
  463.         Setcolor 3,C0%
  464.         Black_flag%=1
  465.       Else
  466.         Setcolor 0,C0%
  467.         Setcolor 3,C3%
  468.         Clr Black_flag%
  469.       Endif
  470.     Endif
  471.     ' these following commands valid when only one window is present
  472.     If Windows!=False
  473.       ' CNTL+C = reprint the screen
  474.       If C%=3
  475.         @Clean_up
  476.       Endif
  477.       ' CNTL+F = toggle to/from AltFont
  478.       If C%=6
  479.         If Nonsystem_text_flag!=False
  480.           ' if no loaded AltFont, load one
  481.           If Alt_font_flag%=0
  482.             @Degas_loader
  483.             @Font_checker
  484.           Else
  485.             ' switch to last selected AltFont
  486.             Nonsystem_text_flag!=True
  487.             Font%=Alt_font%
  488.             @Tidy
  489.             @Initialize_font(Font%)
  490.           Endif
  491.         Else
  492.           ' else switch back to last selected system font
  493.           Nonsystem_text_flag!=False
  494.           Font%=Standing_font%
  495.           @Tidy
  496.           @Initialize_font(Font%)
  497.         Endif
  498.         @Clean_up
  499.       Endif
  500.       ' CNTL+M = increase screen margin
  501.       ' NOTE: <Return> also passes a chr$(13) to the console
  502.       ' and will shift the margins...
  503.       If C%=13
  504.         ' margin must be in units = Bitplane Words
  505.         ' otherwise, you will split up the planes
  506.         Add Margin%,2*Dpeek(Line_a_adr%)
  507.         Margin%=Margin% Mod Dpeek(Line_a_adr%-2)
  508.         @Margin
  509.       Endif
  510.       ' CNTL+N = load a new AltFont and install it
  511.       If C%=14
  512.         @Degas_loader
  513.         @Font_checker
  514.         @Clean_up
  515.       Endif
  516.       ' CNTL+P = print the document (or block)
  517.       If C%=16
  518.         @Print
  519.       Endif
  520.       ' CNTL+R = Reset the Current Drive
  521.       If C%=18
  522.         @Drive
  523.         @Ledger_line
  524.       Endif
  525.       ' CNTL+S = save the document (or block)
  526.       If C%=19
  527.         @Save
  528.       Endif
  529.       ' CNTL+T = strip tabs
  530.       If C%=20
  531.         @Tabber
  532.       Endif
  533.       ' CNTL+V = toggle between visible and invisible printing
  534.       If C%=22
  535.         View%=1-View%
  536.       Endif
  537.       ' CNTL+X = toggle between the two system fonts
  538.       If C%=24
  539.         If Font%<2
  540.           Font%=1-Font%
  541.           Standing_font%=Font%
  542.           @Tidy
  543.           @Initialize_font(Font%)
  544.           @Clean_up
  545.         Else
  546.           Print Chr$(7);
  547.         Endif
  548.       Endif
  549.       ' <Esc> = advance to display of next menu line
  550.       If C%=27
  551.         Add Which%,1
  552.         Which%=Which% Mod M_num%
  553.         @Ledger_line
  554.       Endif
  555.       ' <Tab> = retreat to display of previous menu line
  556.       If C%=9
  557.         Sub Which%,1
  558.         If Which%<0
  559.           Which%=M_num%-1
  560.         Endif
  561.         Which%=Which% Mod M_num%
  562.         @Ledger_line
  563.       Endif
  564.       ' CNTL+<=> = show location-in-document of the top screen line
  565.       If C%=29
  566.         @Data_line
  567.         @Little_key_reader
  568.         @Ledger_line
  569.       Endif
  570.       ' number key used for multiple page or line advances or retreats
  571.       If C%>48 And C%<58
  572.         Index%=Index%+(Jmp%*(C%-48)*Heading%)
  573.         @Screen_print
  574.       Endif
  575.       ' ALT+M = decrease screen margin
  576.       If Cc%=50
  577.         ' margin must be in units = Bitplane Words
  578.         ' otherwise, you will split up the planes
  579.         Sub Margin%,2*Dpeek(Line_a_adr%)
  580.         Margin%=Margin% Mod Dpeek(Line_a_adr%-2)
  581.         @Margin
  582.       Endif
  583.       ' little SBR to check for cursor keypad commands
  584.       ' (double_key is used by other routines than this one)
  585.       @Double_key
  586.       ' FuncKeys assigned to up to ten AltFonts
  587.       ' you could, I suppose, have twenty fonts loaded using
  588.       ' the shifted FuncKeys, but what do you need twenty fonts for...?
  589.       If Cc%>58 And Cc%<69
  590.         If Nonsystem_text_flag!=True
  591.           Font%=Cc%-57
  592.           If Font%<Hi_font%+2
  593.             @Tidy
  594.             @Initialize_font(Font%)
  595.             @Clean_up
  596.           Else
  597.             Print Chr$(7);
  598.           Endif
  599.         Else
  600.           Print Chr$(7);
  601.         Endif
  602.       Endif
  603.       ' <Undo> = Kexit% = KEY EXIT
  604.       If Cc%=97
  605.         Kexit%=1
  606.       Endif
  607.       ' <Help> = convert document type (1stWord<==>Ascii)
  608.       If Cc%=98
  609.         @Convert
  610.       Endif
  611.     Endif
  612.     ' CNTL+Q = Search forward
  613.     If C%=17
  614.       Searches%=0
  615.       @Search
  616.     Endif
  617.     ' ALT+Q = Search backward
  618.     If Cc%=16
  619.       Searches%=-1
  620.       @Search
  621.     Endif
  622.     '  CNTL+W = open a second window or, if open, toggle between windows
  623.     If C%=23
  624.       ' open a second window
  625.       If Windows!=False
  626.         Which%=10
  627.         @Ledger_line
  628.         Windows!=True
  629.         Window%=1
  630.         Active_window%=Window%
  631.         @Set_up_windows
  632.       Else
  633.         ' switch active windows
  634.         Active_window%=1-Window%
  635.         @Window(Window%,Windex%(Window%))
  636.         Window%=Active_window%
  637.         @Window(Window%,Windex%(Window%))
  638.       Endif
  639.     Endif
  640.     ' all these commands effective only if two windows are open
  641.     If Windows!=True
  642.       ' ALT+W = unwindow (close the non-active window)
  643.       If Cc%=17
  644.         @Unwindow
  645.       Endif
  646.       ' <Undo> = KEY EXIT
  647.       If Cc%=97
  648.         @Unwindow
  649.         Kexit%=1
  650.       Endif
  651.       ' cursor keys: document move in windows
  652.       ' functionally equivalent to Double_key SBR
  653.       If Cc%=80
  654.         Heading%=1
  655.         Jmp%=Dpeek(Max_line_adr%)
  656.         Windex%(Window%)=Windex%(Window%)+Jmp%
  657.         @Window(Window%,Windex%(Window%))
  658.       Endif
  659.       If Cc%=72
  660.         Heading%=-1
  661.         Jmp%=Dpeek(Max_line_adr%)
  662.         Windex%(Window%)=Windex%(Window%)-Jmp%
  663.         @Window(Window%,Windex%(Window%))
  664.       Endif
  665.       If Cc%=77
  666.         Heading%=1
  667.         Jmp%=1
  668.         Windex%(Window%)=Windex%(Window%)+Jmp%
  669.         @Window(Window%,Windex%(Window%))
  670.       Endif
  671.       If Cc%=75
  672.         Heading%=-1
  673.         Jmp%=1
  674.         Windex%(Window%)=Windex%(Window%)-Jmp%
  675.         @Window(Window%,Windex%(Window%))
  676.       Endif
  677.       If Cc%=71
  678.         Heading%=1
  679.         Jmp%=Dpeek(Max_line_adr%)
  680.         Windex%(Window%)=0
  681.         @Window(Window%,Windex%(Window%))
  682.       Endif
  683.       If Cc%=119
  684.         Heading%=-1
  685.         Jmp%=Dpeek(Max_line_adr%)
  686.         Windex%(Window%)=Top%-Jmp%
  687.         @Window(Window%,Windex%(Window%))
  688.       Endif
  689.       ' <-> or <+> re-size windows
  690.       ' more headaches than any other piece of this code:
  691.       ' (or maybe I just had a headache that day, doanno)
  692.       ' re-sizing the screen windows involves both windows
  693.       ' since to shrink one is the grow the other, and vice versa
  694.       ' window 1 is the top window; window 0 is the bottom window
  695.       If (Window%=0 And C%=43) Or (Window%=1 And C%=45)
  696.         If Windhi%(1)>1
  697.           ' clear the ledger_line of top window
  698.           Dpoke Max_line_adr%,Windhi%(1)+1
  699.           Dpoke Shifter_adr%,Windtop%(1)
  700.           Print At(1,Windhi%(1)+1);
  701.           @Clear
  702.           ' increase the size of the bottom window
  703.           Dpoke Max_line_adr%,Windhi%(0)+1
  704.           Dpoke Shifter_adr%,Windtop%(0)
  705.           Sub Windtop%(0),Ram_line%(Font%)
  706.           @Clear_window(0)
  707.           Add Windhi%(0),1
  708.           Dpoke Max_line_adr%,Windhi%(0)+1
  709.           Dpoke Shifter_adr%,Windtop%(0)
  710.           ' reprint the bottom window
  711.           @Window(0,Windex%(0))
  712.           ' shrink the top window parameters...
  713.           Dpoke Max_line_adr%,Windhi%(1)+1
  714.           Dpoke Shifter_adr%,Windtop%(1)
  715.           @Clear_window(1)
  716.           Sub Windhi%(1),1
  717.           ' ... and re-print it
  718.           @Window(1,Windex%(1))
  719.           ' note that the number of window lines (Windhi) has to be
  720.           ' temporarily increased by one to erase the window ledger_line along
  721.           ' with the window itself in each case
  722.         Endif
  723.       Endif
  724.       ' this is a little easier...
  725.       If (Window%=1 And C%=43) Or (Window%=0 And C%=45)
  726.         If Windhi%(0)>1
  727.           Dpoke Shifter_adr%,Windtop%(1)
  728.           Add Windhi%(1),1
  729.           Dpoke Max_line_adr%,Windhi%(1)+1
  730.           @Clear_window(1)
  731.           @Window(1,Windex%(1))
  732.           Add Windtop%(0),Ram_line%(Font%)
  733.           Dpoke Shifter_adr%,Windtop%(0)
  734.           Dpoke Max_line_adr%,Windhi%(0)
  735.           @Clear_window(0)
  736.           Sub Windhi%(0),1
  737.           Dpoke Max_line_adr%,Windhi%(0)+1
  738.           @Window(0,Windex%(0))
  739.         Endif
  740.       Endif
  741.     Endif
  742.     ' clear these values to avoid endless repetition
  743.     Clr Cc%
  744.     Clr C%
  745.     Clr Flag%
  746.   Until Kexit%>0
  747. Return
  748. Procedure Double_key
  749.   Clr Offset%
  750.   Stoff%=Index%
  751.   If Cc%=75
  752.     Heading%=-1
  753.     Jmp%=1
  754.     Index%=Index%-Jmp%
  755.     If Index%<1
  756.       Index%=1
  757.       @Screen_print
  758.     Else
  759.       ' the BMOVE command shifts the screen down one line...
  760.       Bmove Xbios(2),Xbios(2)+Ram_line%(Font%),Affected_screen%
  761.       @Home
  762.       @Clear
  763.       ' ...and print a new top print line
  764.       Print Type$(Index%);
  765.     Endif
  766.   Endif
  767.   If Cc%=77
  768.     ' used by other SBR's, but it's the inverse of the above:
  769.     ' shifts the screen up one line and prints new bottom line
  770.     @Bumper
  771.   Endif
  772.   If Cc%=80
  773.     Heading%=1
  774.     Jmp%=Max_line%(Font%)-1
  775.     Index%=Index%+Jmp%
  776.     @Screen_print
  777.   Endif
  778.   If Cc%=72
  779.     Heading%=-1
  780.     Jmp%=Max_line%(Font%)-1
  781.     Index%=Index%-Jmp%
  782.     @Screen_print
  783.   Endif
  784.   If Cc%=71
  785.     Heading%=1
  786.     Jmp%=Max_line%(Font%)-1
  787.     Index%=1
  788.     @Screen_print
  789.   Endif
  790.   If Cc%=119
  791.     Heading%=-1
  792.     Jmp%=Max_line%(Font%)-1
  793.     Index%=Top%-Max_line%(Font%)+1
  794.     @Screen_print
  795.     Print At(1,Max_line%(Font%));
  796.     @Clear
  797.   Endif
  798.   If Cc%=115
  799.     Heading%=-1
  800.     Jmp%=12
  801.     Index%=Index%-12
  802.     @Screen_print
  803.   Endif
  804.   If Cc%=116
  805.     Heading%=1
  806.     Jmp%=12
  807.     Index%=Index%+12
  808.     @Screen_print
  809.   Endif
  810.   Offset%=Index%-Stoff%
  811. Return
  812. Procedure Bumper
  813.   Heading%=1
  814.   Jmp%=1
  815.   Index%=Index%+Jmp%
  816.   If Index%>Top%-Max_line%(Font%)+1
  817.     Index%=Top%-Max_line%(Font%)+1
  818.     @Screen_print
  819.     @Ledger_line
  820.   Else
  821.     Bmove Xbios(2)+Ram_line%(Font%),Xbios(2),Affected_screen%
  822.     ' locate at last line, clear it, print new last line
  823.     Print At(1,Max_line%(Font%));Chr$(27);"K";Type$(Index%+Max_line%(Font%)-1);
  824.   Endif
  825. Return
  826. '
  827. ' ****************************************************************************
  828. ' *                          SECTION 3: SCREEN ROUTINES                      *
  829. ' ****************************************************************************
  830. '
  831. Procedure Tidy
  832.   Cls
  833.   ' boy! that was easy
  834. Return
  835. ' sets up the visible and invisible screens:
  836. ' the visible screen is the monitor screen and/or its memory image
  837. ' the invisible screen is a screen sized area of memory beginning on
  838. ' an even-256-byte boundary. All screen printing is done to the logical
  839. ' screen. To print invisibly, define the off_screen area as the logical
  840. ' screen. Use Xbios(5,L:logical_screen_address,L:physical_screen_address,-1)
  841. ' then, print to the "invisible" logical screen. Repeat the Xbios 5 call
  842. ' to swap the screens back again (to the "visible" screen). Then, either
  843. ' BMOVE the "invisible" screen to the "visible" screen or use GET (before
  844. ' switching back) and PUT (after switching back) to transfer the screen.
  845. Procedure Set_up
  846.   Physical%=Xbios(2)
  847.   Logical%=Xbios(3)
  848.   Page1%=Physical%
  849.   Page2%=Varptr(Offscreen$)+255 And &HFFFFFF00
  850. Return
  851. Procedure Screen_print
  852.   If View%=0
  853.     @Set_up
  854.     ' moves what's on the monitor to the off_screen memory area
  855.     Bmove Page1%,Page2%,32000
  856.     ' prints to the off_screem memory, leaving
  857.     ' the old logical screen on the monitor
  858.     Void Xbios(5,L:Page2%,L:Logical%,-1)
  859.   Endif
  860.   T%=Max_line%(Font%)
  861.   ' clears the screen but leaves the cursor at the end of the printing area
  862.   ' (this saves the menu ledger_line from being cleared)
  863.   Print At(80,T%);Chr$(27);"d";
  864.   ' bring it back home
  865.   @Home
  866.   ' check the indices on the type strings
  867.   ' (you guessed it right: he must be a physicist,
  868.   ' because he has to check the boundary conditions...)
  869.   @Check
  870.   ' now we can print the strings...
  871.   If T%-1+Index%=>Top%
  872.     I%=0+Index%
  873.     Repeat
  874.       Print Type$(I%);
  875.       Inc I%
  876.     Until I%>Top%
  877.   Else
  878.     I%=0+Index%
  879.     Repeat
  880.       Print Type$(I%);
  881.       Inc I%
  882.     Until I%=>T%+Index%
  883.   Endif
  884.   If View%=0
  885.     ' first, capture from the off_screen screen...
  886.     Sget Patch$
  887.     ' ...then, return the monitor to the usual configuration...
  888.     Void Xbios(5,L:Logical%,L:Page1%,-1)
  889.     ' wait... wait... wait...
  890.     Vsync
  891.     ' ...then slap the off_screen patch on the monitor.
  892.     Sput Patch$
  893.     ' garbage collection (more neatness) but probably slows it down a little
  894.     Patch$=""
  895.   Endif
  896. Return
  897. Procedure Check
  898.   If Index%>Top%-Max_line%(Font%)+1
  899.     Index%=Top%-Max_line%(Font%)+1
  900.   Endif
  901.   If Index%<1
  902.     Index%=1
  903.   Endif
  904. Return
  905. ' prints the menu ledger_line
  906. Procedure Ledger_line
  907.   ' switch to system font
  908.   @Font_check_in
  909.   ' locate, switch to inverse video
  910.   @Message(Inv$)
  911.   ' the "5" parameter forces the console driver to print all characters as
  912.   ' characters; none are intrepreted as console codes, giving full access
  913.   ' to all 256 characters of the ST's ascii set. Very handy...
  914.   For Z%=1 To Len(T$(Which%))
  915.     Void Bios(3,5,Asc(Mid$(T$(Which%),Z%,1)))
  916.   Next Z%
  917.   ' switch to normal video output
  918.   Print Norm$;
  919.   ' return to text printing font
  920.   @Font_check_out
  921. Return
  922. ' these two SBR must be used in pairs
  923. Procedure Font_check_in
  924.   ' eliminate any screen margin
  925.   Dpoke Shifter_adr%,0
  926.   ' if an AltFont, select for appropriate system font
  927.   If Font%>1
  928.     Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  929.   Endif
  930. Return
  931. Procedure Font_check_out
  932.   ' restore AltFont
  933.   If Font%>1
  934.     Lpoke Font_data_adr%,Font_data_address%(Font%)
  935.   Endif
  936.   ' restore screen margin, if any
  937.   Dpoke Shifter_adr%,Margin%
  938. Return
  939. ' shifts the screen margin
  940. Procedure Margin
  941.   ' margin must be in units = Bitplane Words
  942.   ' otherwise, you will split up the planes
  943.   Dpoke Shifter_adr%,Margin%
  944.   @Screen_print
  945. Return
  946. Procedure Clean_up
  947.   @Screen_print
  948.   @Ledger_line
  949. Return
  950. ' console code to home the cursor without erasing the screen
  951. Procedure Home
  952.   Print Chr$(27);"H";
  953. Return
  954. ' console code to clear a line from the cursor position to end
  955. Procedure Clear
  956.   Print Chr$(27);"K";
  957. Return
  958. ' when using a 16-pixel-high font on color monitor, we have 12-1/2 lines,
  959. ' except that the half-line looks silly, so we shorten the size of the screen
  960. Procedure Check_screen(Z%)
  961.   If Max_line%(Z%)=11
  962.     Affected_screen%=(Max_line%(Z%)-1)*Ram_line%(Z%)
  963.   Else
  964.     Affected_screen%=32000-Ram_line%(Z%)*2
  965.   Endif
  966. Return
  967. '
  968. ' ****************************************************************************
  969. ' *                            SECTION 4: FONT ROUTINES                      *
  970. ' ****************************************************************************
  971. '
  972. Procedure Find_linea_address
  973.   ' start in the lower memory; this ought to be low enough
  974.   I%=&H28FE
  975.   Repeat
  976.     ' increment by words
  977.     Add I%,2
  978.     ' GEM is sluggish about updating the Line A Tables, so...
  979.     ' Hit him TWICE
  980.     Graphmode 2
  981.     Graphmode 2
  982.     First%=Dpeek(I%)
  983.     ' Hit him TWICE
  984.     Graphmode 3
  985.     Graphmode 3
  986.     Second%=Dpeek(I%)
  987.     ' Hit him TWICE
  988.     Graphmode 4
  989.     Graphmode 4
  990.     Third%=Dpeek(I%)
  991.     ' this just to reset the write mode
  992.     Graphmode 1
  993.     Graphmode 1
  994.     ' until you find a match
  995.   Until First%=1 And Second%=2 And Third%=3
  996.   ' if a memory location changes with the write mode, then it's
  997.   ' the location 36 bytes above the Line A Table Address!
  998.   ' Ok, so it's crude... but it WORKS!
  999.   Let Line_a_adr%=I%-36
  1000.   ' there's more than one way to skin a Line_a_address
  1001.   ' in GFA3: Line_a_adr%=L~a     ! Gee, that was easy!
  1002. Return
  1003. Procedure Font_checker
  1004.   ' only do it if the attempt to load a font file was successful
  1005.   If Filegot%=1
  1006.     @Tidy
  1007.     @Initialize_font(Font%)
  1008.     ' sets the flags for AltFont
  1009.     Nonsystem_text_flag!=True
  1010.     If Alt_font_flag%=0
  1011.       Alt_font_flag%=1
  1012.     Endif
  1013.   Endif
  1014. Return
  1015. Procedure Font_fitter
  1016.   ' the table of font header addresses (at 444, 448, 452, 456 bytes below
  1017.   ' Line-A), are initialized differently on the two system monitors,
  1018.   ' so a slightly different routine is needed to find the address of the
  1019.   ' the other system font on each monitor system. Two of these four table
  1020.   ' address slots are going to be empty (one is for a GEM-loaded GDOS font,
  1021.   ' and one is always empty to show that it's always empty!
  1022.   ' This type of logic is called "GEM-THINK")
  1023.   If Rez%=2
  1024.     Dim Font_header%(4)
  1025.     For I%=0 To 3
  1026.       Font_header%(I%)=Lpeek(Line_a_adr%-456+I%*4)
  1027.       ' the Icon font header remains in ROM; we're looking for the one
  1028.       ' that has a "shadow" or image placed somewhere below the basepage
  1029.       ' also, we're looking for a different font than the one currently
  1030.       ' initialized by GEM (current font header address is tabled
  1031.       ' 460 bytes below Line_a, just below the table of four font header
  1032.       ' addresses at 444, 448, 452, and 456 bytes below the Line-A address)
  1033.       ' and, of course, we don't want one of the empty GDOS slots...
  1034.       ' so that's why all the IFfies...
  1035.       If Font_header%(I%)<>0 And Font_header%(I%)<Basepage And Font_header%(I%)<>Lpeek(Line_a_adr%-460)
  1036.         Let Next_font_header_adr%=Font_header%(I%)
  1037.       Endif
  1038.     Next I%
  1039.     This_font_header_adr%=Lpeek(Line_a_adr%-460)
  1040.     Other_font_data_address%=Lpeek(Next_font_header_adr%+76)
  1041.   Else
  1042.     ' it's a lot easier in color...
  1043.     This_font_header_adr%=Lpeek(Line_a_adr%-460)
  1044.     Let Next_font_header_adr%=Lpeek(This_font_header_adr%+84)
  1045.     Other_font_data_address%=Lpeek(Next_font_header_adr%+76)
  1046.   Endif
  1047.   ' the Zero Font is my term for the other (or non_native) system font
  1048.   Font%=0
  1049.   Font_data_address%(Font%)=Other_font_data_address%
  1050.   If Rez%=2
  1051.     ' on the monochrome monitor, the 8x8 other system font gives you
  1052.     ' 50 lines of print with 8-pixel-high characters, needs good eyes
  1053.     Cell_height%(Font%)=8
  1054.     Max_line%(Font%)=49
  1055.     Ram_line%(Font%)=640
  1056.   Else
  1057.     ' on the color monitor, the 8x16 system font gives you
  1058.     ' 12 lines of print with 16-pixel-high characters, good for bad eyes
  1059.     Cell_height%(Font%)=16
  1060.     Max_line%(Font%)=11
  1061.     Ram_line%(Font%)=2560
  1062.   Endif
  1063.   ' the One Font is my term for the native system font
  1064.   Font_size%(Font%)=1
  1065.   Font%=1
  1066.   Font_data_address%(Font%)=Lpeek(Font_data_adr%)
  1067.   ' only the cell_height varies between the two monitors
  1068.   If Rez%=2
  1069.     Cell_height%(Font%)=16
  1070.   Else
  1071.     Cell_height%(Font%)=8
  1072.   Endif
  1073.   ' everything else is the same
  1074.   Max_line%(Font%)=24
  1075.   Ram_line%(Font%)=1280
  1076.   Font_size%(Font%)=0
  1077.   Standing_font%=Font%
  1078. Return
  1079. Procedure Initialize_font(X%)
  1080.   ' place these tabled characteristics of the font
  1081.   ' in the Line A Tables for the PRINT command to use
  1082.   Dpoke Max_line_adr%,Max_line%(X%)
  1083.   Dpoke Ram_line_adr%,Ram_line%(X%)
  1084.   Dpoke Cell_height_adr%,Cell_height%(X%)
  1085.   Lpoke Font_data_adr%,Font_data_address%(X%)
  1086.   If X%>1
  1087.     Alt_font%=X%
  1088.   Endif
  1089.   ' adjust the screen for each font used
  1090.   @Check_screen(X%)
  1091. Return
  1092. Procedure Degas_loader
  1093.   ' holder for the loaded data
  1094.   Dega$=String$(2050,0)
  1095.   ' I have since discovered that many PD Degas fonts are odd sizes,
  1096.   ' either more than 2050 bytes, or less. Loading the long ones will,
  1097.   ' of course, crash all this, so you might want to enlarge the
  1098.   ' loading string. Best to run them through HUD's FONTEDIT.PRG,
  1099.   ' after which they WILL be 2050 bytes long...
  1100.   '
  1101.   ' as a protection against punching data right on through the end
  1102.   ' of the reserved memory area, let's make this string too long...
  1103.   Dega$=String$(3000,0)
  1104.   Showm
  1105.   Clr Filegot%
  1106.   ' save the program path$
  1107.   Old_path$=Path$
  1108.   ' mask for font files
  1109.   Path$=Dr$+D_path$+"*.FNT"
  1110.   Fileselect Path$,"",L_font$
  1111.   ' reset the program path$
  1112.   Path$=Old_path$
  1113.   If Len(L_font$)>1
  1114.     Bload L_font$,Varptr(Dega$)
  1115.     Filegot%=1
  1116.   Else
  1117.     Goto Fontout
  1118.   Endif
  1119.   ' if there are already ten fonts loaded, replace the tenth with the new one
  1120.   If Hi_font%>9
  1121.     Hi_font%=9
  1122.   Endif
  1123.   ' before loading, we repeat the transfer of the now approriately
  1124.   ' sized system font into the font_data, so we have characters 128-255.
  1125.   ' this time they'll be the right size for the font, of course.
  1126.   Bmove Font_data_address%(Font%),Varptr(Font$(Hi_font%)),4096
  1127.   ' the loaded font is always the same size as the current font
  1128.   Font_size%(Hi_font%+2)=Font_size%(Font%)
  1129.   ' assign the new font its program font_handle
  1130.   Font%=Hi_font%+2
  1131.   ' set the font_data_address
  1132.   Font_data_address%(Font%)=Varptr(Font$(Hi_font%))
  1133.   Defmouse 2
  1134.   ' the DEGAS font format must first be translated into the GEM font format!
  1135.   ' in GEM, the font is a raster image: all first scan lines of all
  1136.   ' characters, followed by all second scan lines of all characters, etc.
  1137.   ' in DEGAS, each character is saved: all the scan lines for A, followed
  1138.   ' by all the scan lines for B, etc. These routines re-leave to GEM format.
  1139.   ' (in GFA3: BYTE{} is much faster than PEEK() and POKE!)
  1140.   ' these routines ignore the enabling switch for half-height fonts
  1141.   ' in the DEGAS format. If the cell_height is 8, every other line is
  1142.   ' loaded into the font_data, but the results may not be pleasing
  1143.   ' unless the font was carefully designed to work both ways...
  1144.   '
  1145.   ' it would be easy to modify this routine to load some GEM fonts;
  1146.   ' all you would have to do is skip this re-leaving process! However,
  1147.   ' those GEM fonts would have to have the following characteristics:
  1148.   ' cell_height of 16, width 8, equal-spacing, full set of characters 0-127.
  1149.   '
  1150.   ' this first routine is for cell_height=16
  1151.   If (Rez%=2 And Font_size%(Font%)=0) Or (Rez%=1 And Font_size%(Font%)=1)
  1152.     J%=0
  1153.     Repeat
  1154.       K%=0
  1155.       Repeat
  1156.         ' inserts the DEGAS font_data into the GEM font_data format
  1157.         Poke Varptr(Font$(Hi_font%))+K%*256+J%,Peek(Varptr(Dega$)+K%+J%*16)
  1158.         Inc K%
  1159.       Until K%=16
  1160.       Inc J%
  1161.     Until J%=128
  1162.     Cell_height%(Font%)=16
  1163.     If Rez%=2
  1164.       Max_line%(Font%)=24
  1165.       Ram_line%(Font%)=1280
  1166.     Else
  1167.       Max_line%(Font%)=11
  1168.       Ram_line%(Font%)=2560
  1169.     Endif
  1170.   Else
  1171.     ' the second routine is for cell_height=8
  1172.     J%=0
  1173.     Repeat
  1174.       K1%=0
  1175.       K2%=0
  1176.       Repeat
  1177.         Poke Varptr(Font$(Hi_font%))+K1%*256+J%,Peek(Varptr(Dega$)+K2%+J%*16)
  1178.         Inc K1%
  1179.         ' skips over a line of font_data, reading only every other line
  1180.         Inc K2%
  1181.         Inc K2%
  1182.       Until K2%=16
  1183.       Inc J%
  1184.     Until J%=128
  1185.     Cell_height%(Font%)=8
  1186.     If Rez%=2
  1187.       Max_line%(Font%)=49
  1188.       Ram_line%(Font%)=640
  1189.     Else
  1190.       Max_line%(Font%)=24
  1191.       Ram_line%(Font%)=1280
  1192.     Endif
  1193.   Endif
  1194.   Defmouse 0
  1195.   '
  1196.   ' Now, if you really want to live dangerously...
  1197.   ' you could change the native GEM system font data,too,
  1198.   ' that is, the font that is used for alerts, fileselects, etc.
  1199.   ' This is also the font that is used by GFA's TEXT command, so
  1200.   ' that replacing it with a DEGAS font would allow the new font
  1201.   ' to be manipulated using the GFA DEFTEXT command, so that you could
  1202.   ' dash in, replace it, use it with the TEXT command, then slap the
  1203.   ' system font back in place (to avoid later embarassment).
  1204.   ' It is the font whose font header address is found 460 bytes below
  1205.   ' the Line_a_address; unfortunately, the font data itself remains
  1206.   ' in ROM, so we can't just BMOVE the data to that address! Think of
  1207.   ' the crashes we could have if we could write to the ROM! Wow!
  1208.   ' At any rate, the font whose header address is at Line_a-460 bytes
  1209.   ' is the font that GEM uses and that GFA uses for the TEXT command.
  1210.   ' First, we save the ROM addresses (only once --- never again)
  1211.   '  If Never_again%=0
  1212.   '  ' the address of the font data is 76 bytes deep into the header...
  1213.   '    Adr%=Lpeek(L~a-460)+76
  1214.   '    ' we'll need to be able to restore the ROM address on exit
  1215.   '    Restorer%=Lpeek(Adr%)
  1216.   '    Never_again%=1
  1217.   ' Endif
  1218.   ' this will insert the font data of the most recently loaded font
  1219.   ' If Never_again%>0
  1220.   '   ' if it's the right size (same as the native system font)
  1221.   '   If Font_size%(Font%)=0
  1222.   '     Lpoke Adr%,Font_data_address%(Font%)
  1223.   '   Endif
  1224.   ' Endif
  1225.   ' If you wanted to preserve the new GEM font, you have to be able to
  1226.   ' keep the font data in a reserved area protected from other programs,
  1227.   ' that is, in a memory-resident accessory, like FONTRIX.ACC does...
  1228.   ' Or, you could use MALLOC to protect the data from GEM, if you
  1229.   ' can get it to work, that is. Interesting crashes result.
  1230.   ' However, you could easily use this code to change the GEM font
  1231.   ' in a program and then restore the system font on program exit,
  1232.   ' thus having a custom font for each program...
  1233.   '
  1234.   ' ok, let's get back to what we were doing in the first place...
  1235.   '
  1236.   ' increment the index for the next font to be loaded
  1237.   Add Hi_font%,1
  1238.   Fontout:
  1239.   Hidem
  1240. Return
  1241. '
  1242. ' ****************************************************************************
  1243. ' *                          SECTION 5: WINDOW ROUTINES                      *
  1244. ' ****************************************************************************
  1245. '
  1246. ' Basically, the text window is simple: you tell the shifter chip how far
  1247. ' down the screen to start the window [Windtop%(Window%)] and you keep track
  1248. ' of how many lines the window area contains [Windhi%(Window%)+1]. The rest
  1249. ' is mere housekeeping. The window ledger_line is not included in the count
  1250. ' of window lines in Windhi%()+1, but must be kept track of separately...
  1251. '
  1252. ' initial window set-up for two equal-size windows
  1253. Procedure Set_windows
  1254.   Windhi%(0)=((Max_line%(Font%)-3)\2)
  1255.   Windhi%(1)=((Max_line%(Font%)-3)\2)
  1256.   ' the top window (window 1) starts at the top of the screen
  1257.   Windtop%(1)=0
  1258.   ' the bottom window (window 0) starts below its ledger_line
  1259.   ' the ledger-line is not included in the count of window lines
  1260.   Windtop%(0)=(Windhi%(0)+2)*Ram_line%(Font%)
  1261. Return
  1262. Procedure Set_up_windows
  1263.   ' no margin possible in only one or several of multiple windows,
  1264.   ' since whole screen is affected by the shift
  1265.   Dpoke Shifter_adr%,0
  1266.   ' clears the screen except for menu ledger_line and leaves the cursor there
  1267.   Print At(80,Max_line%(Font%));Chr$(27);"d";
  1268.   ' start with the document split at the same point in both windows
  1269.   Windex%(0)=Index%
  1270.   Windex%(1)=Index%
  1271.   @Set_windows
  1272.   Window%=0
  1273.   @Window(Window%,Windex%(Window%))
  1274.   Window%=1
  1275.   @Window(Window%,Windex%(Window%))
  1276. Return
  1277. Procedure Wind_title(Z%)
  1278.   ' switch to system font
  1279.   Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  1280.   ' print the window ledger_line in inverse and return
  1281.   Print At(1,Dpeek(Max_line_adr%)+1);Inv$;String$(80,32);Chr$(13);
  1282.   ' active window indicated with arrow marker "==>"
  1283.   If Z%=Active_window%
  1284.     Print " ==>  WINDOW: ";Z%+1;"   FILE: ";File$;"   LINE: ";Windex%(Z%);"/";Top%-1;" <== ";Norm$;
  1285.   Else
  1286.     Print " WINDOW: ";Z%+1;"   FILE: ";File$;"   LINE: ";Windex%(Z%);"/";Top%-1;Norm$;
  1287.   Endif
  1288.   ' switch to current font
  1289.   Lpoke Font_data_adr%,Font_data_address%(Font%)
  1290. Return
  1291. Procedure Unwindow
  1292.   ' keep the your place in the text that was shown in the active window
  1293.   Index%=Windex%(Window%)
  1294.   ' reset the screen for full height
  1295.   Dpoke Max_line_adr%,Max_line%(Font%)
  1296.   ' reset the window flag
  1297.   Windows!=False
  1298.   ' reset the menu ledger_line
  1299.   Clr Which%
  1300.   ' restore any margin selected before there were two windows
  1301.   Dpoke Shifter_adr%,Margin%
  1302.   ' reprint the screen
  1303.   @Tidy
  1304.   @Clean_up
  1305. Return
  1306. Procedure Clear_window(Z%)
  1307.   ' binary move of blank memory to clear only the window area
  1308.   If View%=0
  1309.     Bmove Varptr(Eraser$),Page2%+Windtop%(Z%),(Windhi%(Z%)+1)*Ram_line%(Font%)
  1310.   Else
  1311.     Bmove Varptr(Eraser$),Physical%+Windtop%(Z%),(Windhi%(Z%)+1)*Ram_line%(Font%)
  1312.   Endif
  1313. Return
  1314. Procedure Window(X%,Y%)
  1315.   ' maintain invisible updating
  1316.   If View%=0
  1317.     @Set_up
  1318.     Bmove Page1%,Page2%,32000
  1319.     Void Xbios(5,L:Page2%,L:Logical%,-1)
  1320.   Endif
  1321.   ' set up the Line A Tables for this window
  1322.   Dpoke Shifter_adr%,Windtop%(X%)
  1323.   Dpoke Max_line_adr%,Windhi%(X%)
  1324.   ' clear the window
  1325.   @Clear_window(X%)
  1326.   ' home the cursor
  1327.   @Home
  1328.   ' print the text in the window area
  1329.   T%=Dpeek(Max_line_adr%)
  1330.   If Y%>Top%-T%+1
  1331.     Windex%(X%)=Top%-T%+1
  1332.   Endif
  1333.   If Y%<1
  1334.     Windex%(X%)=1
  1335.   Endif
  1336.   Y%=Windex%(X%)
  1337.   ' notice that we MUST NOT print carriage returns in multiple windows
  1338.   If T%-1+Y%=>Top%
  1339.     I%=0+Y%
  1340.     Repeat
  1341.       Print At(1,I%-Y%+1);Left$(Type$(I%),Len(Type$(I%))-2);
  1342.       Inc I%
  1343.     Until I%>Top%
  1344.   Else
  1345.     I%=0+Y%
  1346.     Repeat
  1347.       Print At(1,I%-Y%+1);Left$(Type$(I%),Len(Type$(I%))-2);
  1348.       Inc I%
  1349.     Until I%>T%+Y%
  1350.   Endif
  1351.   ' set the window one line larger...
  1352.   Dpoke Max_line_adr%,Windhi%(X%)+1
  1353.   ' ...so we can print the window ledger_line...
  1354.   @Wind_title(X%)
  1355.   ' ...then reset it.
  1356.   Dpoke Max_line_adr%,Windhi%(X%)
  1357.   ' if we're printing invisibly, update the monitor display
  1358.   If View%=0
  1359.     Sget Patch$
  1360.     Void Xbios(5,L:Logical%,L:Page1%,-1)
  1361.     Vsync
  1362.     Sput Patch$
  1363.     Patch$=""
  1364.   Endif
  1365. Return
  1366. '
  1367. ' ****************************************************************************
  1368. ' *                           SECTION 6: PRINT ROUTINES                      *
  1369. ' ****************************************************************************
  1370. '
  1371. Procedure Print
  1372.   Clr P_done%
  1373.   Clr P_count%
  1374.   Showm
  1375.   Repeat
  1376.     @Alert(3,"  |Align Your Printer|  to Top of Form|  and Turn it ON.|  ",1," OK ",Dummie%)
  1377.     ' note: we have to re-print the screen to remove the alert box when
  1378.     ' original rez=0 and current rez=1, just like GFA2's editor doesn't do
  1379.     @Screen_print
  1380.     ' make sure the dummie turned the printer on
  1381.     If Out?(0)=0
  1382.       ' give him repeat chances to turn it on...
  1383.       If P_count%>0
  1384.         @Alert(2,"  |Abort This Print|  Operation?|  ",2," No | Yes ",Dummie%)
  1385.         If Dummie%=2
  1386.           P_done%=1
  1387.           P_skip%=1
  1388.         Endif
  1389.       Else
  1390.         @Alert(3,"  |Your Printer| Is NOT On.|  ",1," OK ",Dummie%)
  1391.       Endif
  1392.       @Screen_print
  1393.       Inc P_count%
  1394.     Else
  1395.       ' this SBR used by PRINT and SAVE
  1396.       @Double_duty
  1397.       P_done%=1
  1398.     Endif
  1399.   Until P_done%>0
  1400.   Defmouse 0
  1401.   Hidem
  1402.   @Yellow_off
  1403.   ' give the user a chance to formfeed the tractor
  1404.   If P_skip%=0
  1405.     Lprint Chr$(13);
  1406.     @Alert(2,"  |Insert Formfeed?|  ",1," Yes | No ",Dummie%)
  1407.     If Dummie%=1
  1408.       Lprint Chr$(12);
  1409.     Endif
  1410.   Else
  1411.     P_skip%=0
  1412.   Endif
  1413.   Index%=Hindex%
  1414.   If Black_flag%=1 And Rez%<>2
  1415.     Setcolor 1,&H770
  1416.   Endif
  1417.   @Screen_print
  1418. Return
  1419. ' this sets the highlight color for a selected block:
  1420. ' a yellow highlight when the background color is white and
  1421. ' a medium blue highlight when the background color is black
  1422. Procedure Yellow_on
  1423.   If Rez%<>2
  1424.     If Black_flag%=1
  1425.       Setcolor 1,&H5
  1426.     Endif
  1427.     Print Chr$(27);"c1";
  1428.   Endif
  1429. Return
  1430. Procedure Yellow_off
  1431.   If Rez%<>2
  1432.     Print Chr$(27);"c0";
  1433.   Endif
  1434. Return
  1435. ' self-explanatory, don't you think?
  1436. Procedure Perf_skip
  1437.   For L%=1 To 3
  1438.     Lprint
  1439.   Next L%
  1440. Return
  1441. '
  1442. ' ****************************************************************************
  1443. ' *                            SECTION 7: SAVE ROUTINES                      *
  1444. ' ****************************************************************************
  1445. '
  1446. Procedure Save
  1447.   @Double_duty
  1448.   @Yellow_off
  1449.   If Black_flag%=1 And Rez%<>2
  1450.     Setcolor 1,&H770
  1451.   Endif
  1452.   Index%=Hindex%
  1453.   @Screen_print
  1454. Return
  1455. Procedure Mark_line(Ml%)
  1456.   Mck%=Ml%-Index%+1
  1457.   If Mck%=>1 And Mck%=<Max_line%(Font%)
  1458.     Print At(1,Mck%);Inv$;Left$(Type$(Ml%),Len(Type$(Ml%))-2);Chr$(32);Norm$;
  1459.   Endif
  1460. Return
  1461. Procedure Unmark_line(Ml%)
  1462.   Mck%=Ml%-Index%+1
  1463.   If Mck%=>1 And Mck%=<Max_line%(Font%)
  1464.     Print At(1,Mck%);Norm$;Left$(Type$(Ml%),Len(Type$(Ml%))-2);Chr$(32);
  1465.   Endif
  1466. Return
  1467. '
  1468. ' this routine works with both PRINT and SAVE routines:
  1469. ' while it may be confusing following the trail of two FUNCTIONS
  1470. ' through the code, it saves duplication of several Kb's of code
  1471. '         FUNCTION=19=SAVE         FUNCTION=16=PRINT
  1472. '
  1473. Procedure Double_duty
  1474.   ' save the index of the existing memo line
  1475.   Owch%=Which%
  1476.   ' set a function for print or save
  1477.   Function%=C%
  1478.   ' save the top line of the existing screen for return when done
  1479.   Hindex%=Index%
  1480.   ' querry all or part?
  1481.   @Alert(2,"  |Entire Document|Or Marked Block?|  ",1,"Block| All ",Complete%)
  1482.   ' querry for perf-skip if function is print
  1483.   Clr Perfer%
  1484.   If Function%=16
  1485.     @Alert(2,"  |Set Perf-Skip? |  ",1," ON | OFF ",Perfer%)
  1486.   Endif
  1487.   ' reprint the screen after every alert because GEM won't clear it in
  1488.   ' low resolution switched to medium
  1489.   @Screen_print
  1490.   ' first half of this big IFfie is for the entire document option
  1491.   If Complete%=2
  1492.     ' starting index is beginning of file
  1493.     Stindex%=1
  1494.     ' finishing index is end of file
  1495.     Fnindex%=Top%
  1496.     ' for saving the file to disc
  1497.     If Function%=19
  1498.       Showm
  1499.       Fileselect Path$,"",Saver$
  1500.       If Len(Saver$)>1
  1501.         Defmouse 2
  1502.         Open "O",#1,Saver$
  1503.         ' this reprints the screen with lines highlighted in color or dotties
  1504.         @Screen_setup
  1505.         @Yellow_off
  1506.         ' this adds the zero-th type$ to the file, because ascii=>1stWord
  1507.         ' conversion needs this line to set the WP flag for 1stWord
  1508.         ' otherwise, you just get an extra CR at the head of the file
  1509.         Print #1,Type$(0);
  1510.         ' this does the real work
  1511.         @File_saver
  1512.       Endif
  1513.     Endif
  1514.     ' for printing the file
  1515.     If Function%=16
  1516.       ' skip three lines
  1517.       If Perfer%=1
  1518.         @Perf_skip
  1519.       Endif
  1520.       ' again, set up the screen with color highlight lines or dotties
  1521.       @Screen_setup
  1522.       ' this does the real work
  1523.       @File_print
  1524.     Endif
  1525.     Defmouse 0
  1526.     Hidem
  1527.     ' this JMP skips over all the rest of this procedure
  1528.     ' which is concerned with saving and printing BLOCKS only
  1529.     Goto The_bottom
  1530.   Else
  1531.     ' this option allows the user to mark a block:
  1532.     ' PLEASE NOTE: the end-of-block marked line is INCLUDED in the block,
  1533.     ' unlike many programs' conventional usage for block-marking in which
  1534.     ' the start of the mark is excluded from the block, OK?
  1535.     '
  1536.     ' put up the memo with block-marking commands
  1537.     Which%=4
  1538.     @Ledger_line
  1539.     ' and an alert to the same effect...
  1540.     @Alert(1," <CNTL>+D to Move Marker Down; |  <CNTL>+U to Move Marker Up. |      <CNTL>+A for START; |    <CNTL>+Z for LAST LINE. |  ",1," OK ",Dummie%)
  1541.     ' reprint the screen
  1542.     @Screen_print
  1543.     ' start the marked line at the top of the screen
  1544.     Marked_line%=Index%
  1545.     @Mark_line(Marked_line%)
  1546.     ' look for input
  1547.     Repeat
  1548.       C$=Inkey$
  1549.       If Len(C$)=2
  1550.         Cc%=Asc(Right$(C$))
  1551.         Key_flag!=True
  1552.       Endif
  1553.       If Len(C$)=1
  1554.         C%=Asc(C$)
  1555.       Endif
  1556.       ' move the mark down
  1557.       If C%=4
  1558.         ' unmark the marked line
  1559.         @Unmark_line(Marked_line%)
  1560.         ' increment the line number to be marked
  1561.         Add Marked_line%,1
  1562.         ' if it goes off the screen to the bottom...
  1563.         If Marked_line%-Index%=>Max_line%(Font%)
  1564.           ' scroll the screen first...
  1565.           Index%=Marked_line%
  1566.           @Screen_print
  1567.         Endif
  1568.         ' then mark the new line
  1569.         @Mark_line(Marked_line%)
  1570.       Endif
  1571.       ' as above, only for moving up
  1572.       If C%=21
  1573.         @Unmark_line(Marked_line%)
  1574.         Sub Marked_line%,1
  1575.         If Marked_line%<Index%
  1576.           Index%=Marked_line%
  1577.           @Screen_print
  1578.         Endif
  1579.         @Mark_line(Marked_line%)
  1580.       Endif
  1581.       ' set the starting index, with one bell to confirm to user
  1582.       If C%=1
  1583.         Stindex%=Marked_line%
  1584.         St_set%=1
  1585.         Print Chr$(7);
  1586.       Endif
  1587.       ' set the finishing index, with two bells to confirm to user
  1588.       If C%=26
  1589.         Fnindex%=Marked_line%
  1590.         Fn_set%=1
  1591.         Print Chr$(7);
  1592.         Pause 8
  1593.         Print Chr$(7);
  1594.       Endif
  1595.       ' if things get screwed up, start all over again...
  1596.       If Stindex%>Fnindex% And Fn_set%=1 And St_set%=1
  1597.         @Alert(3," |     Try Again! | Re-Mark the Block! | ",1,"Sorry",Dummie%)
  1598.         Clr St_set%
  1599.         Clr Fn_set%
  1600.         Clr Stindex%
  1601.         Clr Fnindex%
  1602.         @Screen_print
  1603.         @Mark_line(Marked_line%)
  1604.       Endif
  1605.       ' if a two-byte key message has been sent,
  1606.       ' read it with the same double-key procedure
  1607.       ' used by the main program, and move the mark along with it
  1608.       If Key_flag!=True
  1609.         @Double_key
  1610.         @Unmark_line(Marked_line%)
  1611.         Add Marked_line%,Offset%
  1612.         @Mark_line(Marked_line%)
  1613.         Clr Offset%
  1614.         Key_flag!=False
  1615.       Endif
  1616.       ' clear the trigger variables to prevent repetition
  1617.       Clr C%
  1618.       Clr Cc%
  1619.       ' until you get it right!
  1620.     Until Fn_set%=1 And St_set%=1
  1621.   Endif
  1622.   ' set up the screen to start with the beginning of the block
  1623.   Index%=Stindex%
  1624.   ' reprint the screen with highlight color or dotties
  1625.   @Screen_setup
  1626.   Clr St_set%
  1627.   Clr Fn_set%
  1628.   Defmouse 2
  1629.   ' saving a block as a file
  1630.   If Function%=19
  1631.     Showm
  1632.     Fileselect Path$,"",Saver$
  1633.     Hidem
  1634.     If Len(Saver$)>1
  1635.       Open "O",#1,Saver$
  1636.       @File_saver
  1637.     Else
  1638.       Goto The_bottom
  1639.     Endif
  1640.   Endif
  1641.   Pindex%=Stindex%
  1642.   Twofer!=False
  1643.   If Function%=16
  1644.     @File_print
  1645.   Endif
  1646.   The_bottom:
  1647.   @Yellow_off
  1648.   Which%=Owch%
  1649.   @Ledger_line
  1650.   Clr Function%
  1651. Return
  1652. ' printing the file to line device or disc is pretty routine stuff, ok?
  1653. ' but the visual display is not so simple
  1654. ' the purpose of the exercise is to maintain
  1655. ' the printing of lines in highlight color or dotties,
  1656. ' scrolling the screen up as each line is sent to the device,
  1657. ' if the screen is scrollable, and if it isn't, then
  1658. ' we unhighlight or de-dottie it as it is sent off!
  1659. ' that's, well, less simple... four routines to get it done:
  1660. '
  1661. ' first of all, the actual printer routine...
  1662. Procedure File_print
  1663.   Clr Control%
  1664.   Odd!=False
  1665.   Deffill 1,2,1
  1666.   @Yellow_off
  1667.   For I%=Stindex% To Fnindex%
  1668.     Lprint Type$(I%);
  1669.     ' this routine does the highlights
  1670.     @Highlight(I%)
  1671.     ' six line perf-skip
  1672.     If (I%-Pindex%) Mod 60=0 And Twofer!=True
  1673.       If Perfer%=1
  1674.         @Perf_skip
  1675.         @Perf_skip
  1676.       Endif
  1677.     Endif
  1678.     Twofer!=True
  1679.     P$=Inkey$
  1680.     Exit if Asc(P$)=16
  1681.   Next I%
  1682.   ' unhighlight the last one..
  1683.   @Highlight(I%)
  1684.   P_done%=1
  1685. Return
  1686. ' the second, essentially the same as the file printing routine
  1687. Procedure File_saver
  1688.   Clr Control%
  1689.   Odd!=False
  1690.   Deffill 1,2,1
  1691.   @Yellow_off
  1692.   For I%=Stindex% To Fnindex%
  1693.     Print #1,Type$(I%);
  1694.     ' this routine does the highlights
  1695.     @Highlight(I%)
  1696.   Next I%
  1697.   ' unhighlight the last one..
  1698.   @Highlight(I%)
  1699.   Close #1
  1700. Return
  1701. ' here's where it gets interesting:
  1702. ' now, this sets up an initial screen with highlight color or dotties
  1703. Procedure Screen_setup
  1704.   ' reprint the screen
  1705.   @Screen_print
  1706.   ' turn on the highlight or the dotties
  1707.   @Yellow_on
  1708.   Deffill 1,2,1
  1709.   ' figure out where to place the (invisible) cursor
  1710.   If Index%=Stindex%
  1711.     @Home
  1712.   Else
  1713.     Print At(1,Stindex%-Index%+1);
  1714.   Endif
  1715.   ' calculate the print offset, if any
  1716.   Profset%=Stindex%-Index%
  1717.   ' print the highlit lines
  1718.   I%=Stindex%
  1719.   Repeat
  1720.     Print Type$(I%);
  1721.     If Rez%=2
  1722.       Graphmode 2
  1723.       Pbox 0,(I%-Stindex%+Profset%)*Cell_height%(Font%),(Len(Type$(I%))-1)*8,(I%-Stindex%+1+Profset%)*Cell_height%(Font%)
  1724.       Graphmode 1
  1725.     Endif
  1726.     Inc I%
  1727.     Exit if I%>Fnindex%
  1728.   Until I%=>T%+Index% Or I%>Top%
  1729. Return
  1730. ' and this does the actual highlighting and unhighlighting after screen_setup
  1731. ' it is indexed to the actual type$ number being printed (as its parameter)
  1732. Procedure Highlight(H%)
  1733.   ' it's different for the two kinds of highlighting
  1734.   ' dotties have to slapped over after the line is printed,
  1735.   ' but color has to be turned on before the line is printed
  1736.   If Rez%=2
  1737.     Prindex%=H%
  1738.     ' scroll if you can...
  1739.     If Prindex%=<Top%-T% And Prindex%=<Fnindex%
  1740.       ' odd! is a first-time skip variable. I called it odd because it is...
  1741.       If Odd!=True
  1742.         Add Index%,1
  1743.       Endif
  1744.       Bmove Xbios(2)+Ram_line%(Font%),Xbios(2),Affected_screen%
  1745.       Print At(1,Max_line%(Font%));Chr$(27);"K";
  1746.       Print At(1,Max_line%(Font%));Type$(Prindex%+Max_line%(Font%));
  1747.       ' if the inserted line is part of the block, then highlight it
  1748.       If Prindex%+Max_line%(Font%)=<Fnindex%
  1749.         Graphmode 2
  1750.         Pbox 0,(Max_line%(Font%)-1)*Cell_height%(Font%),(Len(Type$(Prindex%+Max_line%(Font%)))-1)*8,Max_line%(Font%)*Cell_height%(Font%)
  1751.         Graphmode 1
  1752.       Endif
  1753.       Odd!=True
  1754.     Else
  1755.       ' we have to determine if the screen has ever scrolled in this pass
  1756.       If Odd!=False
  1757.         ' if the screen is unscrollable, un-highlight the line just printed
  1758.         Print At(1,Prindex%-Index%);Chr$(27);"K";Type$(Prindex%-1);
  1759.         ' important to reset the cursor position!
  1760.         Print At(1,Prindex%-Index%-1);
  1761.       Else
  1762.         ' if the screen has scrolled, the type$ to be printed is different
  1763.         Print At(1,Prindex%-Index%);Chr$(27);"K";Type$(Prindex%);
  1764.         Print At(1,Prindex%-Index%-1);
  1765.       Endif
  1766.     Endif
  1767.   Else
  1768.     ' formally, the same as above
  1769.     ' the chief difference is that dottie-boxes are calculated from the
  1770.     ' TOP of the print-line, and colored lines from the BASELINE of print
  1771.     Prindex%=H%
  1772.     If Prindex%=<Fnindex% And Prindex%=<Top%-T%
  1773.       If Odd!=True
  1774.         Add Index%,1
  1775.       Endif
  1776.       Bmove Xbios(2)+Ram_line%(Font%),Xbios(2),Affected_screen%
  1777.       Print At(1,Max_line%(Font%));Chr$(27);"K";
  1778.       If Prindex%+Max_line%(Font%)<=Fnindex%
  1779.         @Yellow_on
  1780.       Endif
  1781.       Print At(1,Max_line%(Font%));Type$(Prindex%+Max_line%(Font%));
  1782.       @Yellow_off
  1783.       Odd!=True
  1784.     Else
  1785.       If Odd!=False
  1786.         Print At(1,Prindex%-Index%);Chr$(27);"K";Type$(Prindex%-1);
  1787.         Print At(1,Prindex%-Index%-1);
  1788.       Else
  1789.         Print At(1,Prindex%-Index%);Chr$(27);"K";Type$(Prindex%);
  1790.         Print At(1,Prindex%-Index%-1);
  1791.       Endif
  1792.     Endif
  1793.   Endif
  1794. Return
  1795. '
  1796. ' ****************************************************************************
  1797. ' *                         SECTION 8: CONVERT ROUTINES                      *
  1798. ' ****************************************************************************
  1799. '
  1800. ' surprizingly fast conversion between the two formats (well, I was surprized)
  1801. Procedure Convert
  1802.   Defmouse 2
  1803.   Showm
  1804.   ' the Flag% is the CNTL key
  1805.   If Flag%=0
  1806.     ' 1stWord==>Ascii
  1807.     ' nothing fancy at first; just put the fixed-space (CHR 32)
  1808.     ' in the plces occupied by the word-processing space (CHR 30)
  1809.     For I%=1 To Top%
  1810.       Ii%=Instr(Type$(I%),Chr$(30))
  1811.       While Ii%<>0
  1812.         Mid$(Type$(I%),Ii%,1)=Chr$(32)
  1813.         Ii%=Instr(Type$(I%),Chr$(30),Ii%+1)
  1814.       Wend
  1815.     Next I%
  1816.     ' you could insert a routine here to remove specific control
  1817.     ' characters from a 1stWord word-processing file (markers for font
  1818.     ' changes, etc.) if you want to create a purely Ascii file, but
  1819.     ' in general the console just ignores them, anyway.
  1820.   Else
  1821.     ' Ascii==>1stWord
  1822.     ' no ruler line is provided because 1stWord will
  1823.     ' load the SAVEd file without one just fine. I say
  1824.     ' let 1stWord write its own headers...
  1825.     '
  1826.     ' This marks the file as a WP-flag=TRUE for 1stWord
  1827.     Type$(0)=Chr$(31)+Cr$
  1828.     ' we're going to have to add an extra line to the end to make this work
  1829.     Type$(Top%+1)=Cr$
  1830.     For I%=1 To Top%
  1831.       ' first we change the CHR 32 to CHR 30...
  1832.       Ii%=Instr(Type$(I%),Chr$(32))
  1833.       While Ii%<>0
  1834.         Mid$(Type$(I%),Ii%,1)=Chr$(30)
  1835.         Ii%=Instr(Type$(I%),Chr$(32),Ii%+1)
  1836.       Wend
  1837.       ' ...then, we look ahead to the next line of text...
  1838.       Nl%=Asc(Type$(I%+1))
  1839.       ' ...to see if it's the start of a paragraph or tabular matter
  1840.       ' or a blank line... (remember, it hasn't been converted yet!)
  1841.       If Nl%<>9 And Nl%<>32 And Nl%<>13 And Nl%<>10
  1842.         ' 1stWord wants every line in a paragraph to end with a (CHR 30) space
  1843.         If Mid$(Type$(I%),Len(Type$(I%))-2,1)<>Chr$(30)
  1844.           Type$(I%)=Left$(Type$(I%),Len(Type$(I%))-2)+Chr$(30)+Cr$
  1845.         Endif
  1846.       Else
  1847.         ' except the last line of a paragraph, which must not!
  1848.         While Mid$(Type$(I%),Len(Type$(I%))-2,1)=Chr$(30)
  1849.           Type$(I%)=Left$(Type$(I%),Len(Type$(I%))-3)+Cr$
  1850.         Wend
  1851.       Endif
  1852.     Next I%
  1853.     ' this produces a 1stWord WP file that can be reformatted by 1stWord
  1854.   Endif
  1855.   Defmouse 0
  1856.   Hidem
  1857.   @Screen_print
  1858. Return
  1859. '
  1860. ' ****************************************************************************
  1861. ' *                             SECTION 9: TAB ROUTINE                       *
  1862. ' ****************************************************************************
  1863. '
  1864. ' The console has a default TAB of eight spaces supplied by character 9.
  1865. ' Since I haven't been able to find where this value is stored for the console
  1866. ' driver to use, I've been unable to figure out how to reset the TAB_value
  1867. ' directly to the console. Any suggestions for a likely POKE are welcome.
  1868. ' Meanwhile, this routine will strip the chr$(9) out of the file the first
  1869. ' time through, replacing them with chr$(1) + a string of spaces. The next time
  1870. ' through only string of spaces is changed. A possible confusion can occur
  1871. ' if you save these de-tabbed modified files and load them to a word-processor!
  1872. ' (depending on its feelings toward embedded control characters...)
  1873. '
  1874. Procedure Tabber
  1875.   @Font_check_in
  1876.   @New_line
  1877.   If Tb%<>0 Or Tabs!=True
  1878.     Otb%=Tb%
  1879.   Endif
  1880.   If Tb%=0 And Tabs!=False
  1881.     Print " <TAB> default eight spaces; how many to assign? ";
  1882.     Temp_flag%=0
  1883.   Else
  1884.     Print " <TAB> is currently ";Str$(Otb%);" spaces; how many to assign? ";
  1885.     Clr Tb%
  1886.     Temp_flag%=1
  1887.   Endif
  1888.   Tb$=""
  1889.   Tbac$=""
  1890.   Repeat
  1891.     Tba$=Inkey$
  1892.     If Asc(Tba$)>47 And Asc(Tba$)<58
  1893.       Tbac$=Tbac$+Tba$
  1894.       Tb%=Val(Tbac$)
  1895.       Print At(52,Max_line%(Font%)+1);"TAB=";Tbac$;" Press <Ret> to enter.";
  1896.     Endif
  1897.     If Asc(Tba$)=8 And Len(Tbac$)>0
  1898.       Tbac$=Left$(Tbac$,Len(Tbac$)-1)
  1899.       Tb%=Val(Tbac$)
  1900.       Print At(52,Max_line%(Font%)+1);"TAB=";Tbac$;" Press <Ret> to enter. ";
  1901.     Endif
  1902.     If Asc(Tba$)=27
  1903.       Tmp%=Len(Tbac$)
  1904.       Tbac$=""
  1905.       Tb%=Val(Tbac$)
  1906.       Print At(52,Max_line%(Font%)+1);"TAB=";Tbac$;" Press <Ret> to enter.";Spc(Tmp%);
  1907.     Endif
  1908.   Until Tba$=Chr$(13)
  1909.   Print Norm$;
  1910.   Showm
  1911.   Defmouse 2
  1912.   If Temp_flag%=0
  1913.     For K%=1 To Top%
  1914.       Ii%=Instr(Type$(K%),Chr$(9))
  1915.       While Ii%<>0
  1916.         Tabs!=True
  1917.         Type$(K%)=Left$(Type$(K%),Ii%-1)+Chr$(1)+String$(Tb%,32)+Right$(Type$(K%),Len(Type$(K%))-Ii%)
  1918.         Ii%=Instr(Type$(K%),Chr$(9),Ii%+1)
  1919.       Wend
  1920.     Next K%
  1921.   Else
  1922.     For K%=1 To Top%
  1923.       Ii%=Instr(Type$(K%),Chr$(1))
  1924.       While Ii%<>0
  1925.         Tabs!=True
  1926.         Type$(K%)=Left$(Type$(K%),Ii%)+String$(Tb%,32)+Right$(Type$(K%),Len(Type$(K%))-Ii%-Otb%)
  1927.         Ii%=Instr(Type$(K%),Chr$(1),Ii%+1)
  1928.       Wend
  1929.     Next K%
  1930.     Defmouse 0
  1931.     Hidem
  1932.   Endif
  1933.   If Tabs!=False
  1934.     Print Chr$(7);
  1935.     @New_line
  1936.     Print " Sorry! There are no TAB's in this file! ";
  1937.     Print Norm$;
  1938.     Pause 100
  1939.   Endif
  1940.   Clr Temp_flag%
  1941.   @Font_check_out
  1942.   @Clean_up
  1943. Return
  1944. Procedure New_line
  1945.   @Message(Inv$+Space$(80))
  1946.   Print At(1,Max_line%(Font%)+1);
  1947. Return
  1948. ' ****************************************************************************
  1949. ' *                         SECTION 10: SEARCH ROUTINE                       *
  1950. ' ****************************************************************************
  1951. '
  1952. ' the necessity of dealing with multiple windows makes this
  1953. ' more than a little messy, and I'm running low on annotation...
  1954. '
  1955. Procedure Search
  1956.   ' set up for the search querry message line
  1957.   ' everything in this mess has to be set differently depending on the Windows!
  1958.   If Windows!=False
  1959.     @Font_check_in
  1960.   Else
  1961.     Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  1962.     Dpoke Max_line_adr%,Dpeek(Max_line_adr%)+1
  1963.   Endif
  1964.   ' print the querry
  1965.   Print At(1,Dpeek(Max_line_adr%)+1);
  1966.   @Clear
  1967.   Print Inv$;String$(80,32);Chr$(13);" Search String: ";
  1968.   ' now let the user input his search$
  1969.   Search$=""
  1970.   Repeat
  1971.     Ss$=Inkey$
  1972.     If Ss$=Chr$(27) Or Ss$=Chr$(8) Or Ss$=Chr$(13)
  1973.       ' GEM convention: <Esc> to clear
  1974.       If Ss$=Chr$(27)
  1975.         Search$=""
  1976.       Endif
  1977.       ' GEM convention: <Backspace> to back up
  1978.       If Ss$=Chr$(8) And Len(Search$)>0
  1979.         Search$=Left$(Search$,Len(Search$)-1)
  1980.       Endif
  1981.     Else
  1982.       ' else append it to search$
  1983.       Search$=Search$+Ss$
  1984.     Endif
  1985.     Print At(17,Dpeek(Max_line_adr%)+1);Search$;"                             ";
  1986.     ' until user presses <Return>
  1987.   Until Ss$=Chr$(13)
  1988.   Print Norm$;
  1989.   If Windows!=False
  1990.     Stpt%=Index%
  1991.   Else
  1992.     Stpt%=Windex%(Window%)
  1993.   Endif
  1994.   ' guess what GOTTIT! is a flag for...
  1995.   Gottit%=0
  1996.   Place%=0
  1997.   Cnt%=0
  1998.   ' this just determines the location of the mid-screen print line
  1999.   K3%=(Dpeek(Max_line_adr%)+1)\2
  2000.   ' this is for the forward search direction
  2001.   If Searches%=0
  2002.     ' set the starting point
  2003.     If Windows!=False
  2004.       K%=Index%
  2005.     Else
  2006.       K%=Windex%(Window%)
  2007.     Endif
  2008.     ' do the search
  2009.     Repeat
  2010.       Place%=Instr(Type$(K%),Search$)
  2011.       While Place%<>0
  2012.         Add Gottit%,1
  2013.         If Windows!=False
  2014.           Index%=K%-K3%
  2015.         Else
  2016.           Windex%(Window%)=K%-K3%
  2017.         Endif
  2018.         ' this will highlight the search$ in inverse video, when you find it
  2019.         If Windows!=False
  2020.           @Font_check_out
  2021.           @Screen_print
  2022.           Print At(1,K%-Index%+1);Left$(Type$(K%),Place%-1);Inv$;Search$;Norm$;Right$(Type$(K%),Len(Type$(K%))-Place%-Len(Search$)+1);
  2023.           @Font_check_in
  2024.         Else
  2025.           Lpoke Font_data_adr%,Font_data_address%(Font%)
  2026.           Dpoke Max_line_adr%,Dpeek(Max_line_adr%)-1
  2027.           @Window(Window%,Index%)
  2028.           Dpoke Max_line_adr%,Dpeek(Max_line_adr%)+1
  2029.           Print At(1,K%-Windex%(Window%)+1);Left$(Type$(K%),Place%-1);Inv$;Search$;Norm$;Right$(Type$(K%),Len(Type$(K%))-Place%-Len(Search$)+1);
  2030.           Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  2031.         Endif
  2032.         ' you wanna continue or cancel?
  2033.         Print At(1,Dpeek(Max_line_adr%)+1);Inv$;String$(80,32);Chr$(13);" Line ";Str$(K%);" of ";Str$(Top%-1);". Continue Searching? (Any Key but <N> or <n>) ";Norm$;
  2034.         ' check the key message
  2035.         @Little_key_reader
  2036.         Exit if Cnt%=78 Or Cnt%=110
  2037.         ' mark a new place and continue...
  2038.         Place%=Instr(Type$(K%),Search$,Place%+1)
  2039.       Wend
  2040.       Exit if Cnt%=78 Or Cnt%=110
  2041.       Add K%,1
  2042.     Until K%>Top%
  2043.     ' calculate lines searched
  2044.     Ls%=K%-Stpt%
  2045.   Else
  2046.     ' this is for the reverse search, just the same but backwards
  2047.     If Windows!=False
  2048.       K%=Index%+Dpeek(Max_line_adr%)+1
  2049.     Else
  2050.       K%=Windex%(Window%)+Dpeek(Max_line_adr%)+1
  2051.     Endif
  2052.     If K%>Top%
  2053.       K%=Top%
  2054.     Endif
  2055.     Repeat
  2056.       Place%=Instr(Type$(K%),Search$)
  2057.       While Place%<>0
  2058.         Add Gottit%,1
  2059.         If Windows!=False
  2060.           Index%=K%-K3%
  2061.         Else
  2062.           Windex%(Window%)=K%-K3%
  2063.         Endif
  2064.         If Windows!=False
  2065.           @Font_check_out
  2066.           @Screen_print
  2067.           Print At(1,K%-Index%+1);Left$(Type$(K%),Place%-1);Inv$;Search$;Norm$;Right$(Type$(K%),Len(Type$(K%))-Place%-Len(Search$)+1);
  2068.           @Font_check_in
  2069.         Else
  2070.           Lpoke Font_data_adr%,Font_data_address%(Font%)
  2071.           Dpoke Max_line_adr%,Dpeek(Max_line_adr%)-1
  2072.           @Window(Window%,Index%)
  2073.           Dpoke Max_line_adr%,Dpeek(Max_line_adr%)+1
  2074.           Print At(1,K%-Windex%(Window%)+1);Left$(Type$(K%),Place%-1);Inv$;Search$;Norm$;Right$(Type$(K%),Len(Type$(K%))-Place%-Len(Search$)+1);
  2075.           Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  2076.         Endif
  2077.         Print At(1,Dpeek(Max_line_adr%)+1);Inv$;String$(80,32);Chr$(13);" Line ";Str$(K%);" of ";Str$(Top%-1);". Continue Searching? (Any Key but <N> or <n>) ";Norm$;
  2078.         @Little_key_reader
  2079.         Exit if Cnt%=78 Or Cnt%=110
  2080.         ' notice that this isn't really backward; it searches forward
  2081.         ' INSIDE each LINE, then the line is decremented to continue searching
  2082.         ' forward through the previous line, going forward backwards... humm
  2083.         Place%=Instr(Type$(K%),Search$,Place%+1)
  2084.       Wend
  2085.       Exit if Cnt%=78 Or Cnt%=110
  2086.       Sub K%,1
  2087.     Until K%=0
  2088.     ' calculate lines searched
  2089.     Ls%=Stpt%-K%
  2090.   Endif
  2091.   If Windows!=False
  2092.     @Font_check_in
  2093.   Else
  2094.     Lpoke Font_data_adr%,Font_data_address%(1-Font_size%(Font%))
  2095.   Endif
  2096.   Print At(1,Dpeek(Max_line_adr%)+1);Inv$;String$(80,32);Chr$(13);
  2097.   ' report results to user
  2098.   If Gottit%=0
  2099.     Print " ";Str$(Ls%);" lines searched. String NOT FOUND! Any Key to Return...";Norm$;
  2100.   Else
  2101.     If Cnt%=78 Or Cnt%=110
  2102.       Print " Line: ";Str$(K%);" Search aborted at ";Str$(Gottit%);" occurrence(s)! Return? (Any Key but <N> or <n>) ";Norm$;
  2103.     Else
  2104.       Print " ";Str$(Gottit%);" occurrence(s) of string! Return? (Any Key but <N> or <n>) ";Norm$;
  2105.     Endif
  2106.   Endif
  2107.   @Little_key_reader
  2108.   ' clean up this mess
  2109.   If Windows!=False
  2110.     If Cnt%<>78 And Cnt%<>110
  2111.       Index%=Stpt%
  2112.       @Clean_up
  2113.     Else
  2114.       @Ledger_line
  2115.     Endif
  2116.   Else
  2117.     Dpoke Max_line_adr%,Dpeek(Max_line_adr%)-1
  2118.     If Cnt%<>78 And Cnt%<>110
  2119.       Windex%(Window%)=Stpt%
  2120.     Endif
  2121.     @Window(Window%,Windex%(Window%))
  2122.   Endif
  2123.   If Windows!=False
  2124.     @Font_check_out
  2125.   Else
  2126.     Lpoke Font_data_adr%,Font_data_address%(Font%)
  2127.   Endif
  2128.   '
  2129.   '  See, didn't I tell you it was going to be messy?!
  2130.   '
  2131. Return
  2132. Procedure Little_key_reader
  2133.   ' read any key
  2134.   Repeat
  2135.     Cnt$=Inkey$
  2136.     Cnt%=Asc(Cnt$)
  2137.   Until Cnt$<>""
  2138. Return
  2139. '
  2140. ' ****************************************************************************
  2141. ' *                        SECTION 11: MISCELLANEOUS ROUTINES                *
  2142. ' ****************************************************************************
  2143. '
  2144. Procedure Too_long_abort
  2145.   Alrt$="    ERROR! FILE TOO LONG!| File Must Be Text File Less|Than "+Ar$+" Bytes With No Lines|  Longer Than 240 Characters!"
  2146.   @Abort(Alrt$)
  2147. Return
  2148. Procedure Non_text_abort
  2149.   Alrt$="    ERROR! NON-TEXT FILE!| File Must Be Text File Less|Than "+Ar$+" Bytes With No Lines|  Longer Than 240 Characters!"
  2150.   @Abort(Alrt$)
  2151. Return
  2152. Procedure Long_line_abort
  2153.   Alrt$="   ERROR! LINES TOO LONG!| File Must Be Text File Less|Than "+Ar$+" Bytes With No Lines|  Longer Than 240 Characters!"
  2154.   @Abort(Alrt$)
  2155. Return
  2156. Procedure Abort(A$)
  2157.   @Alert(3,A$,1,"ABORT",Dummie%)
  2158.   Kexit%=1
  2159. Return
  2160. Procedure Alert(Alert_type%,Alert_text$,Button%,Alert_choice$,Var Alert_choice%)
  2161.   Alert Alert_type%,Alert_text$,Button%,Alert_choice$,Alert_choice%
  2162. Return
  2163. ' save the user's desktop palette
  2164. Procedure Palette_saver
  2165.   For I%=0 To 15
  2166.     Userp$=Userp$+Mki$(Xbios(7,I%,-1))
  2167.   Next I%
  2168. Return
  2169. Procedure Data_line
  2170.   @Font_check_in
  2171.   @New_line
  2172.   Print " Line ";Str$(Index%);" of ";Str$(Top%-1);".   ";File$;": ";Str$(Ex%);" bytes. ";Norm$;
  2173.   Print Norm$;
  2174.   @Font_check_out
  2175. Return
  2176. '
  2177. ' ****************************************************************************
  2178. ' *                           SECTION 12: CLOSE-OUT ROUTINE                  *
  2179. ' ****************************************************************************
  2180. '
  2181. Procedure End
  2182.   ' in case an error occured with a file channel open
  2183.   Close
  2184.   ' re-normalize the shifter chip
  2185.   Dpoke Shifter_adr%,0
  2186.   ' clean the windshield
  2187.   @Tidy
  2188.   ' recall the rodent
  2189.   Showm
  2190.   ' restore the system font
  2191.   If Font%<>1
  2192.     @Initialize_font(1)
  2193.   Endif
  2194.   '
  2195.   ' if you changed the GEM font, too, you BETTER reset this address
  2196.   '  If Never_again%>0
  2197.   '    Lpoke Adr%,Restorer%
  2198.   '  Endif
  2199.   '
  2200.   ' reset the resolution
  2201.   If Rez%<>Original_rez%
  2202.     Void Xbios(5,L:-1,L:-1,Original_rez%)
  2203.   Endif
  2204.   ' reset the colors to user's desktop palette
  2205.   Void Xbios(6,L:Varptr(Userp$))
  2206.   ' turn the automatic character wrap back on
  2207.   Print Over_flow$;
  2208.   ' turn the boundary of filled figures back on
  2209.   Dpoke Contrl,104
  2210.   Dpoke Contrl+6,1
  2211.   Dpoke Intin,1
  2212.   Vdisys
  2213.   ' reset the user's drive
  2214.   Chdrive Use_drive%
  2215.   ' if there was a goof, we want to know what it was...
  2216.   If Err>0
  2217.     Fake_err%=Err
  2218.     Error Fake_err%
  2219.   Endif
  2220.   ' I'm outta here...
  2221.   Edit
  2222. Return
  2223. '
  2224. ' With the addition of a screen editor and keyboard input, this would be a
  2225. ' reasonable framework for a text editor or word processor. I don't really
  2226. ' feel like re-programming EMACS from scratch this year, however... Besides,
  2227. ' it's already been done. I hope ST READER proves useful to you as a tool,
  2228. ' and that its code is more enlightening than it is confusing!
  2229. '
  2230. ' ****************************************************************************
  2231. ' *                                                                          *
  2232. ' *                             S T  R E A D E R                             *
  2233. ' *                               Version 3.10                               *
  2234. ' *                                                                          *
  2235. ' *                               Program Code                               *
  2236. ' *               © 1990 By Sterling K. Webb, SKWare One, Inc.               *
  2237. ' *                   P. O. Box 277, Bunker Hill, IL 62014                   *
  2238. ' *                                                                          *
  2239. ' *                       GFA BASIC © GFA SYSTEMTECHNIK                      *
  2240. ' *                                                                          *
  2241. ' *                                                                          *
  2242. ' ****************************************************************************
  2243. '
  2244. '
  2245. '
  2246. ' ****************************************************************************
  2247. ' *                    SECTION 13: DRIVE SELECTION ROUTINE                   *
  2248. ' *                    Added at the last minute by request                   *
  2249. ' *                   Intended to make life easier if you're                 *
  2250. ' *                    working with ST READER on hard disc                   *
  2251. ' *                    but reading and writing to a floppy                   *
  2252. ' ****************************************************************************
  2253. '
  2254. Procedure Drive_alert
  2255.   Dr%=Gemdos(25)+1
  2256.   Dr$=Chr$(Dr%+64)+":"
  2257.   @Get_dir_path
  2258.   @Default_mask
  2259.   Path$=Dr$+D_path$+Mask$
  2260.   Dra$=" Current Drive: "+Left$(Dr$)+"  | Current Path: "+D_path$+"  | Current Mask: "+Mask$+"  "
  2261.   @Alert(1,Dra$,1," OK |Reset",Dummie%)
  2262.   If Trick!=False
  2263.     @Screen_print
  2264.   Else
  2265.     @Tidy
  2266.   Endif
  2267. Return
  2268. Procedure Drive
  2269.   @Drive_alert
  2270.   If Dummie%=1
  2271.     Goto Drive_out
  2272.   Endif
  2273.   ' switch to system font
  2274.   @Font_check_in
  2275.   ' use the ledger line for input
  2276.   @Message(Inv$+No_flow$+Space$(80))
  2277.   @Message("==> Press <Ret> for current drive. SET DRIVE NOW: ")
  2278.   Repeat
  2279.     ' take one character
  2280.     Drr$=Inkey$
  2281.     If Len(Drr$)=1
  2282.       Select Asc(Drr$)
  2283.         ' current drive
  2284.       Case 13
  2285.         Dr%=Gemdos(25)+1
  2286.         ' upper case A-P
  2287.       Case 65 To 80
  2288.         Dr%=Asc(Drr$)-64
  2289.         ' lower case a-p
  2290.       Case 97 To 112
  2291.         Dr%=Asc(Drr$)-96
  2292.       Default
  2293.         ' notify the screw-ups
  2294.         @Message(Space$(80))
  2295.         @Message(Chr$(7)+"==> NOT A VALID DRIVE! Press any key to continue... ")
  2296.         Repeat
  2297.         Until Inkey$<>""
  2298.         @Message(Space$(80))
  2299.         @Message("==> Press <Ret> for current drive. SET DRIVE NOW: ")
  2300.         Clr Dr%
  2301.       Endselect
  2302.       Select Dr%
  2303.       Case 1 To 16
  2304.         ' construct drive map as a string
  2305.         Map$=Bin$(Bios(10),16)
  2306.         ' in GFA2, it works like this:
  2307.         ' Map$=Bin$(Bios(10))
  2308.         ' While Len(Map$)<16
  2309.         '   Map$="0"+Map$
  2310.         ' Wend
  2311.         ' if it's a connected drive, switch to it, else...
  2312.         If Mid$(Map$,17-Dr%,1)="1"
  2313.           ' this flag to git outta here
  2314.           Dr_flag%=1
  2315.           Chdrive Dr%
  2316.         Else
  2317.           ' notify the screw-ups
  2318.           @Message(Space$(80))
  2319.           @Message(Chr$(7)+"==> NOT A CONNECTED DRIVE! Press any key to continue... ")
  2320.           Repeat
  2321.           Until Inkey$<>""
  2322.           @Message(Space$(80))
  2323.           @Message("==> Press <Ret> for current drive. SET DRIVE NOW: ")
  2324.         Endif
  2325.       Endselect
  2326.     Endif
  2327.   Until Dr_flag%>0
  2328.   Clr Dr_flag%
  2329.   Dr$=Chr$(Dr%+64)+":"
  2330.   @Message(Space$(80))
  2331.   @Message("==> SELECTED DRIVE: "+Dr$+" ")
  2332.   Pause 55
  2333.   ' now, allow for setting a directory or nest of directories
  2334.   ' as a path for the file search
  2335.   Repeat
  2336.     Try_again!=False
  2337.     @Message(Space$(80))
  2338.     @Message(" Press <Ret> for Root (if no path shown). SET PATH NOW: ")
  2339.     @Get_dir_path
  2340.     Ppac$=Left$(D_path$,Len(D_path$)-1)
  2341.     D_path$=Ppac$
  2342.     Print Ppac$;
  2343.     ' take the user's input
  2344.     Repeat
  2345.       Pp$=Inkey$
  2346.       Select Asc(Pp$)
  2347.         ' backspace erase
  2348.       Case 8
  2349.         If Len(Ppac$)>0
  2350.           Ppac$=Left$(Ppac$,Len(Ppac$)-1)
  2351.           @Backup
  2352.         Endif
  2353.         ' escape to clear the path
  2354.       Case 27
  2355.         Ptmp%=Len(Ppac$)
  2356.         Ppac$=""
  2357.         For Tp%=1 To Ptmp%
  2358.           @Backup
  2359.         Next Tp%
  2360.         ' append characters to path
  2361.       Case 33 To 125
  2362.         Print Upper$(Pp$);
  2363.         Ppac$=Ppac$+Upper$(Pp$)
  2364.       Endselect
  2365.       ' until return terminates
  2366.     Until Pp$=Chr$(13)
  2367.     If Len(Ppac$)=0
  2368.       Ppac$="\"
  2369.     Endif
  2370.     Test$=Ppac$
  2371.     If Right$(Test$)<>"\"
  2372.       Test$=Test$+"\"
  2373.     Endif
  2374.     If Exist(Dr$+Test$+"*.*")=True
  2375.       Chdir Ppac$
  2376.       @Get_dir_path
  2377.     Else
  2378.       @Message(Space$(80))
  2379.       @Message(Chr$(7)+"==> "+Dr$+Test$+" does NOT exist or is EMPTY! Press any key to continue... ")
  2380.       Repeat
  2381.       Until Inkey$<>""
  2382.       Ppac$="\"
  2383.       Chdir D_path$
  2384.       @Get_dir_path
  2385.       Try_again!=True
  2386.     Endif
  2387.   Until Try_again!=False
  2388.   If Right$(D_path$,1)<>"\"
  2389.     D_path$=D_path$+"\"
  2390.   Endif
  2391.   Path$=Dr$+D_path$
  2392.   @Message(Space$(80))
  2393.   @Message("==> SELECTED DRIVE AND PATH: "+Path$+" ")
  2394.   Pause 55
  2395.   @Message(Space$(80))
  2396.   @Message("==> Press <Ret> to confirm.    SET MASK NOW: ")
  2397.   @Default_mask
  2398.   Print Mask$;
  2399.   Repeat
  2400.     Mk$=Inkey$
  2401.     Select Asc(Mk$)
  2402.       ' backspace erase
  2403.     Case 8
  2404.       If Len(Mask$)>0
  2405.         Mask$=Left$(Mask$,Len(Mask$)-1)
  2406.         @Backup
  2407.       Endif
  2408.       ' escape to clear the mask
  2409.     Case 27
  2410.       Ptmp%=Len(Mask$)
  2411.       Mask$=""
  2412.       For Tp%=1 To Ptmp%
  2413.         @Backup
  2414.       Next Tp%
  2415.       ' append characters to mask
  2416.     Case 33 To 125
  2417.       Print Upper$(Mk$);
  2418.       Mask$=Mask$+Upper$(Mk$)
  2419.     Endselect
  2420.     ' until return terminates
  2421.   Until Mk$=Chr$(13)
  2422.   @Default_mask
  2423.   Path$=Path$+Mask$
  2424.   @Message(Space$(80))
  2425.   @Message("==> SELECTED: "+Path$+"   Press any key to continue... ")
  2426.   Repeat
  2427.   Until Inkey$<>""
  2428.   ' clear the ledger line
  2429.   @Message(Space$(80))
  2430.   Drive_out:
  2431. Return
  2432. Procedure Get_dir_path
  2433.   D_path$=Dir$(Dr%)
  2434.   D_path$=D_path$+"\"
  2435.   Path$=Dr$+D_path$
  2436. Return
  2437. Procedure Message(A$)
  2438.   Print At(1,Max_line%(Font%)+1);A$;
  2439. Return
  2440. Procedure Backup
  2441.   Print Chr$(27);"D";Chr$(32);Chr$(27);"D";
  2442. Return
  2443. Procedure Default_mask
  2444.   If Len(Mask$)=0
  2445.     Mask$="*.*"
  2446.   Endif
  2447. Return
  2448. ' I thought I might use these somewhere... but I didn't
  2449. Procedure Cursor_off
  2450.   Print Chr$(27);"f";
  2451. Return
  2452. Procedure Cursor_on
  2453.   Print Chr$(27);"e";
  2454. Return
  2455.